tezvyn:

Architecting multi-brand, dark-mode theming

AI-drafted, machine-checkedSource: interviewintermediate
WHAT IT TESTS

scalable theming architecture.

OUTLINE

tier tokens into primitive, semantic, and component layers; components consume semantic tokens; themes swap by remapping semantic-to-primitive on a scope like data-theme.

WHAT THIS TESTS: This evaluates whether you can architect a layered token system so that theming becomes a remapping exercise rather than a fork.

A GOOD ANSWER COVERS: Structure tokens in tiers. Primitive tokens hold the raw values: the full color palette like blue-500, the spacing scale, type sizes. Semantic tokens express roles, such as color-text-default, color-surface-raised, or color-action-primary, and reference primitives rather than literals. Optional component tokens scope further, like button-background, referencing semantic tokens. Components and CSS only ever consume semantic or component tokens exposed as CSS custom properties, never primitives directly. A theme, whether dark mode or a second brand, is then just a different mapping of semantic tokens to primitives. In CSS you set the semantic custom properties on :root for the default, override them under [data-theme="dark"] or a brand attribute, and optionally honor @media (prefers-color-scheme: dark). Because components read only semantic variables, switching the attribute reskins the whole app instantly with no component changes. This keeps the system DRY, scalable to many brands, and easy to audit.

COMMON WRONG ANSWERS: Letting components reference primitives like blue-500 directly, so theming requires touching every component. Duplicating the entire token set per theme instead of remapping the semantic layer. Skipping the semantic tier so there is no stable contract. Recreating the GoRouter-style mistake of rebuilding everything on theme change instead of overriding variables.

LIKELY FOLLOW-UPS: How do you scope a theme to a subtree rather than the whole document. How do you prevent flash of incorrect theme on load. How do component tokens avoid an explosion of names.

ONE CONCRETE EXAMPLE: Components use color: var(--color-text-default). On :root, --color-text-default maps to gray-900; under [data-theme="dark"] it remaps to gray-50. Flipping the attribute swaps text color everywhere with no component edits and no duplicated palettes.

Read the original → penpot.app

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.