Raw hex values in a design file look harmless until the day someone asks for dark mode. Suddenly every color decision made across dozens of components needs to be revisited one by one. A semantic color system prevents that problem entirely, and setting one up correctly from the start costs very little.
What “Semantic” Means
Most color systems start as palettes: a range of blues, some neutrals, a red for errors. That’s the raw material. A semantic system adds a layer on top that names colors by their purpose rather than their appearance.
blue-600 is a palette value. color-action-primary is a semantic token. The palette tells you what a color looks like. The semantic token tells you when to use it.
The distinction matters because design decisions are made in context. A designer specifies “the primary action color for this button,” not “blue-600.” When those two ideas live in the same hex value, every rebrand or theme change has to ripple manually through every component that touches that color.
The Two-Layer Model
A well-structured semantic color system has exactly two layers.
Layer 1: The palette. A finite set of named color values, usually a graduated scale per hue. neutral-100 through neutral-900. brand-400, brand-500, brand-600. error-500. These are never used directly in components.
Layer 2: The semantic tokens. Purpose-named variables that reference palette values. A token like surface-page might point to neutral-50 in light mode and neutral-950 in dark mode. text-default might be neutral-900 in light mode and neutral-100 in dark.
The result: switching themes means changing which palette value each semantic token resolves to. The components themselves don’t change at all.
The palette answers “what does this color look like?” The semantic layer answers “what is this color for?” Both questions need an answer, and they belong on separate levels.
Naming Conventions That Scale
Good semantic names are role-based and technology-agnostic. A few principles hold up well over time.
Name by function, not appearance. text-primary ages better than text-dark. border-focus is clearer than border-blue. The moment a rebrand replaces your blue primary with green, appearance-named tokens become a maintenance liability rather than a shortcut.
Use a noun-role structure. Think in categories: surfaces, text, borders, icons, and actions. surface-page, text-default, border-input, action-primary. This taxonomy makes it obvious where a new token belongs and where an existing one should be found.
Limit nesting depth. One level of qualification is enough in most cases: action-primary, action-secondary, action-destructive. Going deeper produces tokens that feel too specific to use consistently, which encourages hardcoded overrides instead.
Document intent alongside the value. A token named feedback-error with no description is an invitation to use it for anything vaguely red. The definition (“Used for error states, form validation failures, and destructive action confirmations”) is what gives the name force. Without it, you have naming theatre, not a system.
Theming and Dark Mode
This is where semantic tokens pay off. Without them, dark mode is a find-and-replace exercise across every component. With them, it is a single mapping file.
Each semantic token gets two definitions: one for light mode and one for dark. Component code references only the token name. At runtime, the correct palette value resolves based on the active theme.
The same mechanism handles brand themes. A white-label product can swap a single token map rather than re-specifying every component from scratch. If a company rebrands and replaces its core blue with a new hue, updating the palette value that brand-500 refers to propagates everywhere automatically.
Design tokens, particularly when implemented using the W3C Design Tokens format or a tool like Style Dictionary, can be shared between design tools and the codebase. The Figma variables panel and your CSS custom properties stay in sync when the handoff is built around token names rather than hex values.
Trade-offs Worth Knowing
Semantic systems add indirection. There are now two things to learn instead of one: the palette and the token layer. For solo designers or very small products, that overhead sometimes outweighs the benefit. A flat palette with disciplined naming is better than a two-layer system applied inconsistently.
The abstraction also fails when names are too generic. A system built on tokens like color-1, color-2, and color-accent provides none of the semantic clarity the structure promises. The naming work is where most of the value actually lives.
A common failure mode is mixing semantic and palette tokens in component specs. If one component uses text-default and another uses neutral-900 directly, you end up with a hybrid that is harder to maintain than either a pure palette approach or a full semantic one. Consistency in the approach matters more than which approach you choose.
This kind of systematic thinking connects directly to other structural decisions in UI. The same discipline that makes a typographic system coherent applies to color: deliberate decisions at the system level prevent improvised decisions at the component level, and those improvised decisions are what cause interfaces to drift over time.
A Practical Migration Path
Starting from scratch is easier than migrating an existing product. But most projects have a color set that needs restructuring, not wholesale replacement.
A reasonable sequence:
- Audit current colors. Extract every hex value used in components and group visually similar values. This usually reveals redundancy: four slightly different grays doing the same job, or two “primary” blues from separate design phases.
- Rationalise the palette. Reduce to a defensible scale per hue. Name values consistently within each scale.
- Create the semantic layer. Map each UI role to a palette value. Be explicit about what a token is for, not just what it points to.
- Migrate components incrementally. Replace hardcoded values with token references one component type at a time. Buttons and form fields first, then navigation and surface layers.
- Enforce at review. Hardcoded hex values in components should be a flag in code review, not a convention that grows back over time.
This process is worth running alongside a broader UI design principles audit. Color decisions don’t exist in isolation; they interact with hierarchy, contrast, and the consistency principles that hold an interface together.
How Strynal Approaches Semantic Color
When Strynal builds an interface, a token system is part of the deliverable. The design file and the codebase share the same vocabulary from day one: semantic token names exist in Figma variables and in CSS custom properties, both pointing to the same palette values.
Dark mode and theming are always structured in, even when a client doesn’t ask for them upfront. The two-layer structure adds almost no ongoing overhead, and it turns a future “we need dark mode” request from a multi-week rework into a short mapping exercise.
Our UI/UX service covers the full design-to-build scope: token architecture, component systems, and the kind of spatial consistency that a spacing system built on an 8pt grid delivers alongside color structure. If you’re rebuilding an interface or starting from a blank page, get in touch and we’ll walk you through the structure before a single component is designed.