Anti-patterns
Every item here has cost real time on this codebase. None of them throw an error.
Fallback values
padding: var(--space-13, 13px);/* The scale has no 13. Rounded to 12. */
padding: var(--space-12);A fallback hides a missing token instead of fixing it. An undefined custom property with no fallback drops the whole declaration — visibly broken, quickly found. With a fallback it silently ships the literal forever, while reading like a tokenised value. This is how a renamed token generation survived a rewrite here.
A fallback is for a token that genuinely may not be in scope yet — not a hedge against one that no longer exists. If a fallback is doing real work, the token is missing: declare it.
Raw values in product CSS
background: #292929;
color: rgba(255, 255, 255, 0.6);background: var(--color-surface-panel);
color: var(--color-text-secondary);A raw hex in product CSS is an audit failure. Beyond the rule, it opts the element out of the contextual accent: a rule pinned to a violet literal stays violet on the green CMS surface, which is exactly the bug the token tiers exist to prevent.
Overriding the wrong token
.my-surface {
--semantic-primary-default: green;
}.my-surface {
/* Rebind what components actually consume. */
--color-accent-primary: …;
--color-focus-ring: …;
}Custom properties inherit as computed values. A --color-* token declared at :root from a semantic source is substituted once, at the root. Overriding the source further down the tree changes nothing — the descendant inherits the already-computed value.
Scoped theming must rebind every token components consume, not just the source. Verify it by measuring getComputedStyle inside the scope.
Recomposing border rules
border: 1px solid var(--color-border-default);border: var(--border-default-rule);The composed rules exist so a hairline is one decision. Recomposing it by hand is how one surface ends up 1px while its neighbour is 1.5px after a density pass.
Type shorthand without tracking
font: var(--text-overline);font: var(--text-overline);
letter-spacing: var(--font-tracking-label);The font: shorthand resets letter-spacing. Any composite type token that needs tracking has to declare it separately, on the next line, every time.
Decoration in the tab order
<span className="card-preview">
<Button>Primary</Button>
</span><span className="card-preview" inert>
<Button>Primary</Button>
</span>A live preview used as decoration — the cards on the catalogue, for instance — puts real buttons and inputs in the tab order and the accessibility tree unless it is marked inert.
Relatedly: checkbox visuals rendered as aria-hidden spans inside another button must not be promoted to real role="checkbox" elements. Decorative is not interactive, and a control inside a control is invalid HTML.
Touching the renderer
src/builder/renderer/ and src/templates/ are off-limits to design-system work. They render the user's site content, not Sitefold's chrome. A sweep that tokenises them leaks Sitefold's CSS into customers' exported sites.
This is the one rule on this page with no “do” column: the correct action is to leave those directories alone.