Pug Mixins &attributes: A Practical Engineering Decision for Reusable Button Markup in Server‑Rendered Apps
Centralize button markup with Pug mixins and &attributes to keep server‑rendered templates DRY while safely handling attribute merging.
15 Oct 2025, 04:08 UTC

Problem and Takeaway
When a server‑rendered site has dozens of templates, a simple button often appears in many places with slightly different class names or aria attributes. Copy‑pasting the markup leads to drift and maintenance headaches. The practical takeaway is that Pug mixins combined with &attributes let you define the button once and call it with varied attributes in a single line, keeping the templates DRY and reducing errors.
What Is a Pug Mixin?
A mixin is a reusable snippet defined with the syntax mixin name(args) and invoked with +name(args). The + prefix tells Pug to treat the call as a function that emits markup rather than a top‑level element. Mixins have been part of Pug since its Jade days and remain stable in the Pug 3 series, which was renamed from Jade in 2016.
Basic Syntax
Define a mixin:
mixin button(label, variant)
Invoke it:
+button('Save','primary')
The generated HTML will be a <button> element whose class includes the variant.
Merging Caller Attributes with &attributes
Pug lets the invoked mixin receive additional attributes via the &attributes placeholder. The syntax &attributes({key: 'value'}) merges the supplied object into the element’s attributes. Class lists are concatenated, while other duplicate attributes are overridden according to the language specification.
This mechanism lets a single mixin stay flexible: the caller can add data attributes, ARIA roles, or custom classes without changing the mixin definition.
Worked Example: A Centralized Button Component
Suppose we need a button that always uses the base class btn and a variant class such as btn--primary. We want the caller to supply any extra attributes in one line.
// mixin definition
mixin button(label, variant)
// compute the variant class
var className = 'btn btn--' + variant
// emit the button with merged attributes
+tag('button', className, &attributes(attributes))
Calling the mixin with extra attributes:
+button('Save', 'primary')(data-testid='save', aria-label='Save form')
The rendered HTML will be:
<button class="btn btn--primary" data-testid="save" aria-label="Save form">Save</button>
Notice that the class attribute combines the base class with the variant, and the extra attributes are merged exactly as provided.
Escaping and Safety Considerations
Normal interpolation with #{} is HTML‑escaped by default, so string arguments to a mixin are safe from XSS. However, the unescaped !{} and the &attributes placeholder bypass escaping. Use &attributes only with trusted data or pre‑sanitized values, and avoid !{} unless you deliberately need raw HTML.
To verify safety, render a label containing a <script> inside #{} and via !{} and compare the output; the escaped version should escape the script tags while the unescaped version will include them verbatim.
Trade‑off: Whitespace Sensitivity
Pug is whitespace‑sensitive; mixing tabs and spaces or running a generic HTML formatter can unintentionally change the structure of a template. Teams must adopt a consistent indentation policy or use an editor/linter that enforces spaces only. This discipline is a real cost compared to indentation‑free templating engines, but it ensures that the mixin output matches the author’s intent.
Verification Steps
- Install Pug locally:
npm install pug. Run a small template file withpug renderFileor the CLI to see the generated HTML. - Check the installed version with
npm ls pugand confirm it matches the version you intend to use. - Reproduce the button example above and inspect the output for the expected class list and attribute values.
- Test escaping by rendering a label with a
<script>inside#{}versus!{}and verify that only the escaped version escapes the tags. - Confirm attribute precedence by passing a duplicate attribute name (e.g.,
class="foo"in the mixin call andclass="bar"via&attributes) and observe which value appears in the final HTML.
Conclusion
Choosing Pug mixins with &attributes is a deliberate engineering decision for server‑rendered stacks such as Express apps where build simplicity matters. It provides a lightweight way to reuse markup, keep templates DRY, and maintain safety when attributes are handled correctly. For projects that need scoped styles, client‑side state, or type‑checked props, a dedicated component framework may be more appropriate. In a Pug‑centric codebase, defining small, presentational mixins and enforcing a consistent indentation policy gives you reusable components without the overhead of a full UI library.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.