Reusing CSS in Stylus: Parameterized Mixins with Defaults
Learn how to create and use Stylus mixins that accept arguments and default values, reduce duplication, and keep your styles flexible. A step‑by‑step button example shows how to override defaults, import mixins, and validate the output.
13 Apr 2026, 20:55 UTC

Problem
When a project grows, repeating the same CSS rules across many selectors becomes a maintenance nightmare. Hard‑coded values for colors, padding, or border radius make it hard to change a design system element in one place. Developers often write a new class for every button style, even though the underlying structure is identical.
Thesis
Stylus mixins with arguments and default values let you write a single, parameterized block of CSS and reuse it wherever needed. By providing sensible defaults, you keep the mixin useful out of the box while still allowing callers to override any property they care about.
Using Mixins with Defaults
A mixin in Stylus is a block of CSS wrapped in a function‑like syntax. Parameters can be optional; if a caller omits them, the mixin falls back to the default you specify.
// button.styl – mixin definition
button(size = 14px, bg = #0066cc, color = #fff, radius = 4px)
font-size size
padding 0.5em 1em
background bg
color color
border-radius radius
border none
cursor pointer
- size – font size of the button text.
- bg – background color.
- color – text color.
- radius – corner radius.
When you call button() without arguments, Stylus substitutes the defaults. If you supply fewer arguments than parameters, the missing ones are replaced with defaults in order.
Example: Button Component
Below is a minimal file structure that demonstrates how to define, invoke, and override the mixin in different contexts.
/* layout.styl – main stylesheet */
@import 'button'
/* Primary button – uses defaults */
.btn-primary
button()
/* Secondary button – overrides background and radius */
.btn-secondary
button(14px, #666, #fff, 8px)
/* Small button – only overrides size */
.btn-sm
button(12px)
Run the Stylus compiler:
stylus layout.styl -o dist/css
Expected output in dist/css/layout.css (simplified):
.btn-primary{font-size:14px;padding:.5em 1em;background:#0066cc;color:#fff;border-radius:4px;border:none;cursor:pointer}
.btn-secondary{font-size:14px;padding:.5em 1em;background:#666;color:#fff;border-radius:8px;border:none;cursor:pointer}
.btn-sm{font-size:12px;padding:.5em 1em;background:#0066cc;color:#fff;border-radius:4px;border:none;cursor:pointer}
Check the generated CSS carefully: the default values are applied where you didn’t override them, and the overrides appear exactly as specified.
Importing Mixins Across Files
Mixins can be exported from one file and imported elsewhere, enabling modular design systems.
// components/button.styl – export mixin
button(size = 14px, bg = #0066cc, color = #fff, radius = 4px)
font-size size
padding 0.5em 1em
background bg
color color
border-radius radius
border none
cursor pointer
// pages/home.styl – import mixin
@import '../components/button'
.btn-home
button(16px, #ff6600)
Running the compiler on home.styl will generate a button style that uses the imported mixin, demonstrating cross‑file reuse.
Trade‑offs & Limitations
- Generated CSS Size – Each mixin call expands into full CSS. If you call a mixin many times with different arguments, you may end up with a large stylesheet. Use
@extendor!importantsparingly to avoid duplication. - Debugging Complexity – Since mixins generate CSS at compile time, the source of a style can be hard to trace. Add comments or use the Stylus REPL (
stylus -e) to inspect the output of a particular mixin call. - Parameter Mismatch – Passing a string to a numeric parameter (e.g.,
button('large')) will produce a compilation error that may be cryptic. Validate argument types in your build process or add guard clauses in the mixin.
Actionable Checklist
- Define mixins in a dedicated file (e.g.,
mixins.styl) and export them. - Use default values that match your design system’s base style.
- When overriding, pass arguments in the same order as defined; if you only need to change one property, consider naming the parameter for clarity:
button(bg: #ff6600)(Stylus supports named arguments). - Compile with
stylus -wto watch for changes and immediately see the output. - Validate the output by comparing the generated CSS against the expected values, either manually or via a simple test script that greps for key properties.
- Keep an eye on the final CSS size; if it grows beyond your threshold, refactor by extracting common properties into a base class or using
@extend.
Conclusion
Parameterised mixins with defaults are a powerful way to keep your Stylus code DRY, maintainable, and adaptable. By defining a single reusable block, providing sensible defaults, and allowing selective overrides, you can evolve your UI components without scattering style definitions across your codebase. Just remember to monitor generated CSS size and validate mixin calls to avoid hidden bugs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.