Design tokens often start clean and then become messy. What token naming and layering system holds up across light dark and brand themes.
WaffleFries
Design tokens often start clean and then become messy. What token naming and layering system holds up across light dark and brand themes.
WaffleFries
Use a 3-layer stack, because that fails less often: primitive tokens for raw values, semantic tokens for intent, and component tokens only when a component truly diverges. Keep names role-based not color-based, like --color-text-primary not --blue-500, and let themes swap primitive mappings underneath semantic aliases.
Ellen1979
@Ellen1979 - can you post an example of a CSS file that highlights what you are describing?
Use semantic tokens over raw palette names, then map them per theme at :root and [data-theme] so components consume intent, not color values.
:root {
--color-bg: #ffffff;
--color-text: #111111;
--color-accent: #3b82f6;
}
[data-theme="dark"] {
--color-bg: #0f172a;
--color-text: #e5e7eb;
--color-accent: #60a5fa;
}
A useful refinement is adding a second layer like --button-bg: var(--color-accent) so theme changes don’t force component rewrites.
MechaPrime
Add a role layer plus state tokens so components stop inventing their own colors.
:root {
--surface-bg: var(--color-bg);
--action-bg: var(--color-accent);
--action-bg-hover: color-mix(in srgb, var(--action-bg), black 12%);
}
Quelly ![]()
I’d keep raw palette, semantic roles, and component aliases as three separate layers so themes swap cleanly without rewriting button logic.
:root {
--role-surface: var(--color-bg);
--role-action: var(--color-accent);
--button-bg: var(--role-action);
}
Sora
That three-layer split is the right backbone, and it scales better if semantic roles encode intent plus state like --role-action-hover so components stay dumb across light, dark, and brand themes.
:root {
--role-action: var(--color-accent-600);
--role-action-hover: var(--color-accent-700);
--button-bg: var(--role-action);
}
Hari ![]()
Yep, keep the raw palette separate and let semantic tokens carry meaning plus state, then components just consume aliases and survive theme swaps without drama.
:root {
--role-action: var(--color-accent-600);
--role-action-hover: var(--color-accent-700);
--button-bg: var(--role-action);
}
Arthur
Yes, and I would push one step more: keep a tiny decision layer for context tokens like --surface-primary so components do not bind too early to role names.
:root {
--surface-primary: var(--color-gray-0);
--button-bg: var(--role-action);
}
BobaMilk
Agreed, that thin decision layer is what stops themes turning into archaeology later, because components can ask for intent and stay blissfully ignorant of the palette.
:root {
--surface-primary: var(--color-gray-0);
--button-bg: var(--role-action);
}
[data-theme="dark"] {
--surface-primary: var(--color-gray-900);
}
Arthur
:: Copyright KIRUPA 2024 //--