semantic token adoption

situation

component kit with semantic theme variables in some places, raw palette utilities in others, local inline overrides scattered throughout. a theme explorer made a new palette easy to preview, but applying it directly would create two incompatible authorities with no way to change a role consistently. changing "primary action" color meant finding and editing five places using five different names or mechanisms — the source of truth was distributed.

why

the protected invariant is single ownership of visual meaning. when one role can be spelled many ways, no visual decision can be made once and trusted; every refinement becomes an audit of the whole interface. routing accepted palette values through a bounded role-token system keeps the fast preview loop while ensuring each value lands under an owner the next change can address in one place.

invariants

  • tokens name roles, never individual component instances.
  • components consume role tokens through a bounded variant contract.
  • a refinement preserves the incumbent visual identity outside its approved scope; a redesign is named explicitly and replaces the old system fully.
  • local layout utilities do not become hidden theme values.

decision process

candidatereasoningdecision
paste explorer output into component fileseach component becomes its own authorityrejected
add a raw palette utility whenever a surface differssimilar values, no shared audit pathrejected
retain every old alias for safetytwo vocabularies, ambiguous adjustmentsrejected
map accepted values to a small role-token system, then update named variantstoken-to-component trace, coherent themeselected

resulting shape

shared theme defines canvas, surface, text, border, action, destructive, and data roles. components expose intent and state variants mapping to those roles. a route controls only local layout and its final content inset. a role correction changes the token once; a component-state correction changes its variant once.

verification

  1. classify the work as refinement or redesign before choosing values.
  2. render supported theme modes and real interaction/error/loading states.
  3. trace each changed element to a semantic role and component variant.
  4. search for superseded raw values and token aliases after adoption.
  5. inspect nested surfaces for duplicate padding or decorative-wrapper insets.

good and bad

bad

// status badge
<span className="text-emerald-500 bg-emerald-100">active</span>
// elsewhere, a different "active" state
<div className="border-2 border-green-500">running</div>
// in another component, yet another shade
<Button className="bg-[#10b981]">proceed</Button>

emerald-500, green-500, and #10b981 are the same or similar greens, each named differently and maintained independently. changing "active status" color means auditing every file and guessing which hex values were intentional. a designer's correction ("make positive calmer") lands on some surfaces and not others; every fix needs a manual sweep.

good

// status badge
<StatusBadge tone="positive">active</StatusBadge>
// elsewhere, a different "active" state
<Badge tone="positive" variant="outlined">running</Badge>
// another component using the same role
<Button variant="primary">proceed</Button>

each component declares its semantic role (positive, primary, destructive). one token system owns all "positive" surfaces: changing the positive color updates every surface using the positive role. new surfaces inherit the role's colors without inventing new spellings.

search pages

go to any page