# Create a Color Token System With Clear Semantic Roles

By Steven Van · 2026-10-18

Map palette primitives to semantic color roles, verify foreground-background pairs, and review light and dark themes across real component states.

![Conceptual color-token editor with semantic swatches and paired light and dark component previews.](<https://creatorstoolbox.com/images/evergreen/create-a-color-token-system-with-clear-semantic-roles-ui.png>)

*AI-generated conceptual illustration; not a product screenshot, measured result, or factual diagram.*

A palette tells you which colors exist. A color token system tells you where they belong. That distinction becomes important the first time a brand blue appears on a button, a link, a selected tab, and a decorative background, then needs to change in a dark theme.

If every component refers directly to blue-600, changing the brand color can change several unrelated jobs at once. If every component invents its own color, consistency becomes difficult to maintain. Semantic tokens provide a middle layer: names for roles such as primary text, raised surface, interactive border, and danger message.

This guide builds a small token system for a fictional resource-library interface. The worked examples include a search field, a resource card, a primary button, and an error message. The color values are illustrative candidates with a few explicitly calculated contrast ratios, not a claim that a complete interface has passed an accessibility audit.

## Begin with the interface's actual roles

Take a representative screen and mark where color carries a job. Start with text, surfaces, borders, actions, and feedback. Within each group, separate roles only when their behavior genuinely differs.

For text, the library needs primary reading text, secondary descriptive text, text on a filled action, and error text. For surfaces, it needs the page background, card background, and a subdued feedback background. Borders need an ordinary separator role and a stronger control-boundary role.

Do not begin by inventing every possible token in a large design system. A small product may not need five surface elevations or twelve levels of disabled text. Add a role when a real component requires a distinct decision.

Write a one-sentence definition for each role. “Text-secondary: supporting information that remains necessary to understand the item” is better than “lighter text.” The first definition reminds you that secondary does not mean dispensable or unreadable.

## Keep primitive values separate from semantic names

The primitive layer stores reusable color values: navy-900, neutral-0, blue-600, red-700, and so on. These names describe the palette rather than the component's purpose.

The semantic layer maps a role to one of those values. For the light-theme example, text-primary maps to navy-900 at #17263C, surface-page maps to neutral-0 at #FFFFFF, action-primary-fill maps to blue-600 at #2563EB, and action-primary-text maps to white at #FFFFFF.

The danger-text role maps to #B42318 in this example. It should not simply be named red, because its job may require a different red in another theme. A decorative red illustration accent may share the same primitive today but should not automatically share the semantic role.

Components consume semantic names. The primary button uses action-primary-fill and action-primary-text. It does not need to know whether the current theme maps those roles to blue, teal, or another approved value. This keeps a theme change focused on role relationships instead of scattered component overrides.

![The color system separates a primitive value, a semantic role and the component that consumes it.](<https://creatorstoolbox.com/images/evergreen/create-a-color-token-system-with-clear-semantic-roles/color-role-mapping.svg>)

These are illustrative mappings from the fictional light theme. A decorative accent and a danger message can share a primitive without sharing a semantic role.

## Use paired roles where the relationship matters

A foreground color is not accessible or inaccessible in isolation. Its relationship with the background, the content type, and the relevant criterion matters. Document common pairs together.

For the resource library, pair text-primary with surface-page and surface-card. Pair action-primary-text with action-primary-fill. Pair danger-text with the backgrounds on which error messages actually appear. If danger text is allowed on both the page and a tinted panel, verify both combinations.

The example #17263C text on #FFFFFF has a calculated WCAG contrast ratio of approximately 15.23:1. White on #2563EB is approximately 5.17:1. The #B42318 danger text on white is approximately 6.57:1. These calculations use the specified solid sRGB colors; they do not account for an image, transparency, or a different rendered background.

W3C's [Contrast (Minimum) guidance](<https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html>) explains the 4.5:1 requirement for ordinary text and 3:1 for qualifying large text, along with exceptions. Use the unrounded calculation when comparing with a threshold. Do not round a failing value upward into a pass.

### Keep the tested pair beside the role

These ratios are recalculated from the solid sRGB hex values using WCAG relative luminance. Display values are rounded for reading; threshold decisions use the unrounded result.

  Resource-library example color pairs

Role pair | Foreground / background | Calculated ratio |

Light primary text / page | #17263C / #FFFFFF | 15.23:1 |

Primary action text / fill | #FFFFFF / #2563EB | 5.17:1 |

Light danger text / page | #B42318 / #FFFFFF | 6.57:1 |

Dark primary text / page | #F8FAFC / #0F172A | 17.06:1 |

Dark danger text / page | #FDA29B / #0F172A | 9.20:1 |

These five pairs clear the 4.5:1 ordinary-text threshold as specified. They do not approve every palette combination, translucent layer, hover state, or rendered component. The conceptual hero uses a different illustrative palette and is not a sample of these exact values.

![Five specified foreground/background pairs have calculated ratios 15.23, 5.17, 6.57, 17.06 and 9.20 to one.](<https://creatorstoolbox.com/images/evergreen/create-a-color-token-system-with-clear-semantic-roles/color-tested-pairs.svg>)

Ratios are rounded for display from the specified solid sRGB pairs. Threshold decisions use unrounded values; this does not approve every theme state or translucent background.

## Build a small component specimen

Create a page containing the four example components in realistic combinations. A search field should include label, placeholder, typed text, helper message, border, and focus treatment. A card should include heading, description, metadata, and link. The button needs default, hover, focus, pressed, and disabled states where those states exist. The error message needs its actual surrounding surface.

A palette sheet cannot expose all of these relationships. The same border may look adequate around a white field on a white page and disappear when the field sits on a tinted card. The specimen puts those combinations in view.

Use real content lengths and at least one long error message. A small red dot next to a short label is a poor substitute for a full error state. The token system should support the content people will actually read.

Document each component's token references. If a designer cannot tell which semantic token controls an element, the system is not yet clear enough for reliable handoff.

## Treat dark mode as a new mapping

Do not create dark mode by mechanically reversing the palette or subtracting every color from white. The roles stay recognizable, but their values may need different relationships.

For the example dark theme, surface-page becomes #0F172A and text-primary becomes #F8FAFC. That pair has a calculated contrast ratio of approximately 17.06:1. Danger-text can use #FDA29B on that page background, a calculated ratio of approximately 9.20:1. These are candidate pairs, not a complete dark-theme palette.

Review surface-card separately from surface-page. If both use nearly identical values, a card may need a border or another structural cue. If the card is much brighter, it may dominate the page. The right relationship depends on the layout and content hierarchy.

Also review saturated action colors. A brand color that looks balanced on white may become visually harsh on a dark surface. Adjust the role mapping while preserving the brand's broader identity, then recheck the foreground and focus relationships.

## Make state tokens explicit when needed

A single action-fill token may be insufficient if the component changes on hover, press, or selection. Add state-specific roles when they represent a repeatable decision: action-primary-fill-hover, action-primary-fill-pressed, or selection-surface.

Avoid deriving every state by applying a global opacity. Transparency changes the resulting color according to what sits underneath it, which can make contrast and appearance context-dependent. If you use transparency intentionally, document the permitted backgrounds and test the resulting combinations.

Selected and focused are different states. A selected tab identifies the current view; focus identifies the control currently receiving keyboard interaction. The same color can participate in both treatments, but the interface must make both meanings understandable when they occur together.

Disabled controls need a clear product decision too. Do not make an unavailable action so faint that people cannot discover it or understand why it is unavailable. A technical exception in a contrast criterion is not a design goal.

![Selection identifies the current view; keyboard focus identifies the control receiving input. Both must be understandable when they occur together.](<https://creatorstoolbox.com/images/evergreen/create-a-color-token-system-with-clear-semantic-roles/color-selected-focus.svg>)

A semantic name alone proves neither contrast nor behavior. Review the component on its actual adjacent surfaces.

## Check borders, icons, and focus indicators separately

Text contrast is only part of the review. W3C's [Non-text Contrast guidance](<https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html>) addresses visual information needed to identify controls, states, and meaningful graphics, generally requiring 3:1 against adjacent colors with specified exceptions. Not every decorative divider must meet that requirement, so identify what each line is doing.

For the library's search field, decide whether its boundary is necessary to identify the control. For an icon-only action, inspect the icon's relationship to its background. For the focus indicator, inspect the actual adjacent surfaces in each placement rather than testing it on white alone.

A focus ring that works around the primary button may disappear around a dark card. Consider a treatment with an offset or multiple contrasting parts if the product's placements demand it, then verify the actual implementation. Do not label a token “accessible-focus” and assume the name proves the outcome.

Keep decorative and functional border roles separate. That lets a subtle card divider remain visually quiet without forcing a control boundary to inherit the same low-contrast value.

## Never let color carry the whole message

An error needs a readable message, not only a red border. A selected filter needs an additional cue such as a checkmark, text, or clear shape change. A chart series may need labels or patterns as well as different hues.

W3C's [Use of Color guidance](<https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html>) explains why color should not be the sole visual means of conveying information, indicating an action, or distinguishing an element. Treat that principle as a component-design requirement alongside the token values.

For the resource-library error, include an explanatory sentence and an appropriate icon if it helps. For a selected format filter, include a visible check and a programmatically exposed selected state. The semantic token contributes to the message but does not replace the structure and text that carry its meaning.

This also makes the interface easier to understand in poor lighting, on unfamiliar displays, and in monochrome reproductions. Those are useful practical checks even though they do not replace formal accessibility evaluation.

## Implement the mapping where it can be inspected

On the web, CSS custom properties can expose semantic values such as `--text-primary` and `--surface-page`, with theme-specific overrides. MDN's [custom-properties guide](<https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties>) explains declaration and use through the cascade and the `var()` function.

Keep the naming scheme aligned between design documentation and code. If the design file calls a role content-muted while code calls it gray-500, reviewers must translate the system mentally and may miss mismatches.

Automate checks where useful, such as detecting raw hex values outside the token file or calculating approved foreground-background pairs. Treat those checks as support rather than proof of full accessibility. They cannot infer every rendered background, interaction state, or meaning from a token list alone.

When a component needs a new role, ask whether the need is semantic or merely local. A one-off illustration color can stay in the illustration. A repeated “text on emphasized surface” relationship may deserve a shared token.

## Review the system as a set of decisions

Before release, inspect the specimen in light and dark themes, with all interactive states visible, long messages present, and keyboard focus moving through the controls. Verify the actual rendered colors and document the pairs that were checked.

Maintain a short exception list for unusual backgrounds, imagery, and embedded widgets. If a component cannot safely use the standard roles, record why and who owns its review. Hidden exceptions eventually become unexplained palette drift.

The finished system should make a simple question easy to answer: “Which role belongs here, and what other color must it work against?” When the answer is clear, the palette can evolve without turning every component into a separate redesign.

[Read Create a Color Token System With Clear Semantic Roles on Creators Toolbox](<https://creatorstoolbox.com/blog/create-a-color-token-system-with-clear-semantic-roles>)

---
Canonical source: https://creatorstoolbox.com/blog/create-a-color-token-system-with-clear-semantic-roles
