In a component library, what is a component-scoped override token, and when is exposing one better than changing a semantic token?
answer
- reach of the change
- one component, not every role user
- default points at a semantic role
- every exposed token is a promise
- designed alternative look means variant
basics
~20 sA component-scoped override token is a named hook on one component whose default references a semantic token. Setting it changes only that component, so it beats editing the semantic token when the rest of the product must stay as it is.
solid answer
~50 sA **component-scoped override token** is a token that belongs to one library component — say, the selectable card's selected border — whose default value is a reference to a semantic token such as `border.selected`. Left alone, the card follows the theme like everything else. Set by a consumer, it changes that one component and nothing else. That is the right lever when the need is local: a year-end appeal page wants its donation cards outlined in the campaign accent, while checkboxes, table rows and settings cards keep the normal selected color. Editing the semantic token would recolor all of them. The costs are real: each exposed override is a public contract that is hard to rename or remove, too many of them freeze the component's internals, and consumer-chosen colors can break contrast. Expose them for properties consumers repeatedly and legitimately vary; a designed alternative look is a variant instead.
code
json · 17 lines{
"selectable-card": {
"$type": "color",
"border-selected": {
"$value": "{color.border.selected}",
"$description": "Border of a selected card. Defaults to the selected-border role; consumers may override it for one context."
},
"surface-selected": {
"$value": "{color.surface.selected}",
"$description": "Background of a selected card. Override together with text-selected to keep contrast."
},
"text-selected": {
"$value": "{color.text.on-selected}",
"$description": "Text on a selected card."
}
}
}go deeper
Recall the difference in reach: a semantic token changes every component using the role, an override token changes one component where it is set.
Explain why the default must alias a semantic role, how to decide between an override token and a variant, and which properties are safe to expose.
Show judgment about which hooks a component should publish, how contrast is protected when consumers set colors, and how to keep the hook count from freezing internals.
Weigh consumer flexibility against the long-term cost of every published hook, and set a policy for when a recurring override graduates into a variant or a new semantic role.
## Two ways to change how one component looks A library component that consumes a theme can be adjusted at two very different altitudes: - **Change a semantic token.** A semantic token names a role (`border.selected`, `surface.raised`). Changing its value in the theme changes *every* component that uses the role — the whole product moves together, which is exactly what a theme is for. - **Set a component-scoped override token.** A component override token belongs to one component (`selectable-card.border-selected`). Its **default** is a reference to a semantic token, so an untouched component still follows the theme. When a consumer sets it, only that component changes, and only where the consumer set it. The override token is a **hook**: a named, documented place where the library invites adjustment. It is not a new tier of meaning — how token tiers are structured and named is a separate topic — but it is the component's side of the theming contract. ## A worked case A charity donation site runs a year-end appeal. On the appeal page, the donation-amount cards (built from the library's selectable card) should show the appeal accent as their selected border. Everywhere else — the monthly-gift settings, checkboxes in the preferences form, selected rows in the donation history table — the product's normal selected color must stay. | Lever | Reach | Who owns it | Main risk | |---|---|---|---| | Semantic token in the theme | every component using the role | system or theme owners | collateral changes across the product | | Component override token | one component, where it is set | library exposes, consumer sets | token count and a public contract | | Variant | one component, a designed option | library and design | needs design review before it exists | | Reaching into internals | unpredictable | nobody | breaks silently on any refactor | Changing `border.selected` would recolor the checkboxes and table rows too. Setting the card's own `border-selected` on the appeal page changes exactly what was asked for. ## When a library should expose one 1. **A real, recurring need.** More than one consumer, or a documented use such as campaign pages, wants to vary the property. A single request may be better served another way. 2. **A property that can vary safely.** Surfaces, borders, corner radius and inner padding usually can. Properties whose meaning depends on the rest of the palette — an error state, a focus indicator — usually should not be casually overridable. 3. **A semantic default.** The default must reference a semantic token, not a literal. Otherwise the component stops following theme changes the moment the override token exists. 4. **Not a designed alternative.** If design wants a named alternative look with its own reviewed combination of values, that is a **variant**, not an override. ## What each override costs - **It is public API.** Consumers depend on its name and effect; renaming or removing it breaks them, and how that change is classified and released is its own concern. - **Too many freeze the internals.** A component with forty override tokens has published its internal structure under another name; every refactor must preserve all forty. - **Contrast is out of the library's hands.** A consumer can set a background that fails against the component's text. Exposing background and foreground as a documented pair, and saying which combinations were checked, reduces the damage. - **Documentation and testing grow.** Each hook needs a description, a default and at least one example of it being set. ## Across platforms The shape is the same everywhere. On the web, a component-scoped value falls back to the semantic one unless a consumer sets it for a region of the page. On native mobile, a component reads its own entry from the theme object or a style parameter, which defaults to the semantic theme value. In a design editor, the component's own variable can be bound to the semantic one. In each case the rule is identical: **the component-level name defaults to the role**, and overriding it is local. ## A quick decision rule Ask three questions in order: should *every* use of this role change? Then edit the theme. Is this a designed alternative look? Then add a variant. Is it a local, recurring adjustment of one property? Then an override token is the right hook.
- Why must an override token's default be a reference and not a copied value?A copied value is a literal hidden behind a name. The component stops following the theme: when a new theme or mode changes the semantic role, every untouched instance keeps the old value. With a reference, doing nothing still means following the theme, and only consumers who set the override opt out.
- A consumer overrides the selected card's background and the text becomes hard to read. Whose problem is it, and what can the library do?The consumer chose the value, but the library designed the hook. It can expose background and text as a documented pair, state which combinations it checked, and have its guidance tell consumers to override both together. It cannot verify every value a consumer might set, so it makes the safe path the obvious one.
saying these in an interview costs you the question
- To change one component, just edit the semantic token it uses.
- An override token's default can be a copy of today's value.
- Every styled property should get its own override token for flexibility.
- Override tokens are internal details that can be renamed freely.
- Any designed alternative look should be delivered as override tokens.