Base: the element layer
Two working limits of elements(), the mixin that maps a role onto a tag —
part of base/, the layer that owns tag/class parity (see CLAUDE.md’s
Architecture tree).
The one-curve-per-document limitation
The typography module’s scale derivation produces a single tracking curve per document, governed by $tracking-per-doubling. A consumer combining multiple typefaces — for instance, a tight sans, a serif, and a monospace face — all share this one tracking curve. If a design needs negative tracking for one font and positive tracking for another below body size, this single curve cannot serve both. The one-curve-per-document assumption is a stated limit of the module’s architecture.
Which system owns block margins on a claimed tag?
Typography owns both the type properties (size, weight, line-height, spacing) and the flow properties (margin-block) of tags it claims, by default.
When @include type.elements(); is called without arguments, it passes $flow: true to every role it maps. This means typography outputs margin-block for p, h1–h6, ul, ol, etc.
Taking back margin control
If a consumer design system (or prose component) needs to own the margins itself — for instance, to implement a bespoke rhythm stack — it can disable the flow margin output entirely.
To disable it globally for all mapped tags:
@use 'pkg:@erikakers/typography' as type;
@include type.elements($flow: false);To disable it for specific tags only:
Exclude them from the map passed to elements(), and style them individually via the role() mixin:
@use 'pkg:@erikakers/typography' as type;
// A custom element that takes a heading's type but no margins
.custom-title {
@include type.role('h3', $flow: false);
}Tags that normally want a role’s type without flow margins (like summary and legend) can also be styled this way, or included in a custom $elements map with elements($flow: false) so the consumer can own all their block spacing.