Design Tokens
Role-based guidance for using UI Lab foreground, background, accent, and semantic tokens
Design Tokens
UI Lab tokens are role decisions, not a generic light-to-dark palette. A class such as text-foreground-300 or bg-background-900 should explain what the element is doing in the interface: normal text, muted support text, page depth, elevated surface, passive selection, primary action, or feedback.
Using a token is only the first check. The token also needs to fit the UI role. A selected filter chip should usually become a clearer neutral surface; it should not automatically become an accent-filled primary object.
Typography Role Tokens
Component typography uses three family tokens: --font-body, --font-heading, and --font-mono. Components pair those with the existing --text-*, --font-weight-*, and --leading-* scales rather than adding per-component type tokens. The separate .typography class is for long-form reading flow rather than compact UI controls.
Color Token Families
UI Lab's main color work happens through four families:
The background and foreground scales are bounded role scales. Do not read them as "50 is a light background and 950 is dark text." In this site, foreground-50 is the brightest foreground and background-950 is a deep page/root layer in the dark theme.
Foreground Tokens
Use foreground-50 sparingly. It is often too bright for compact controls, filter chips, metadata, secondary actions, and repeated list rows. Most ordinary UI text should start at foreground-300; supporting text usually belongs at foreground-400.
Background Tokens
The site commonly layers background-950 as the page or app shell, background-900 as a secondary layer, and background-800 for elevated panels, cards, popovers, and controls. Borders and dividers commonly use background-700, moving toward background-600 for stronger hover or selected edges.
Accent Restraint
Accent is load-bearing. It should draw attention to the thing the product wants users to understand or do.
Appropriate accent uses:
- Primary actions and CTAs:
bg-accent-600 text-foreground-50 - Links or brand emphasis:
text-accent-500 - Current product/location navigation when it needs brand weight
- Focus rings and small active indicators
- Compact badges that communicate a special product state
Usually inappropriate accent uses:
- Passive selected filter chips with
bg-accent-*orborder-accent-* - Category rows, generic selected pills, inactive toolbar controls, or filter popovers
- Decorative swatches that do not mean primary, brand, focus, or active product state
- Hover states that make an inactive item look more important than the selected item
For passive selected filters, chips, category rows, and toggles, prefer neutral state changes first:
Semantic Tokens
Use semantic families only when the UI is communicating that semantic meaning.
Do not use semantic colors as decoration or as substitute brand colors. If a status needs only low emphasis, pair a subtle semantic fill such as bg-success-600/10 with readable semantic text and a restrained border.
State Recipes
Hover states should clarify affordance without outranking active or selected states. If an unselected item hovers to text-foreground-50 while the selected item sits at text-foreground-300, the hierarchy is backwards.
Token Class Hygiene
Avoid conflicting token classes on the same element or within a single conditional branch:
The same rule applies to text-*, border-*, and state variants such as hover:bg-*. Competing classes make the intended role harder to audit and easier to break during refactors.
Anti-Pattern Checklist
- Accent used as a generic selected chip, filter, category, or toolbar background
foreground-50applied everywhere, especially on compact controls and metadata- Hover state brighter, stronger, or more colorful than the selected state
- Multiple competing
bg-*,text-*, orborder-*token classes on one element - Semantic colors used decoratively instead of for status, feedback, validation, or destructive actions
- A token chosen only because it is valid, not because it fits the element's UI role