Tokens Before Overrides: A Three-Tier Token Architecture In short: Primitive tokens are the raw palette. Semantic tokens say what a value means. Component tokens are the public API. Skip the third tier and every customisation becomes a side effect. The previous lesson ended with a component exposing as a supported customisation point. This lesson is about making those properties a system rather than a pile. Why not SCSS variables For years the standard approach was SCSS variables imported into every component: SCSS variables are resolved at compile time . The build replaces with and the variable no longer exists in the output. Which means: You cannot change it at runtime. Dark mode requires a second compiled stylesheet. A new tenant with a green brand requires a separate build and a separate deployment. A consumer who needs one green button has no hook, so they reach for . Native CSS custom properties are resolved at runtime , live in the DOM, cascade, and can be overridden per element. That is the entire difference, and it is decisive. Keep SCSS if you like it for nesting, mixins, and loops. Just do not use SCSS variables for anything a consumer might want to change. Tier 1: primitive tokens Every raw value the design system allows. Nothing else. Rule: never use a primitive directly in a component. They exist only to build tier two. A component that references has hardcoded a colour with extra steps — it will not respond to a theme change. Tier 2: semantic tokens What a value means . This is the layer a theme swaps. A developer building an intake form asks for "the primary colour", not "blue 600". When the brand changes, this file changes and everything follows. Tier 3: component tokens — the public API This is the tier people skip, and it is the one that prevents side effects. Each component declares its own tokens on , defaulting to tier two. The component's CSS uses only its own tokens. Why the third tier matters The dispatch team wants their "Approve dispatch" button green instead of blue. Without tier three , the only lever is the semantic token: That is not one green button. It is every button, every active tab, every focused input ring, every link, and every selected row inside that subtree. The consumer wanted one thing and changed forty. With tier three , the change is scoped to exactly one component: Note this works because of ordinary cascade rules: the consumer's rule and the library's rule target the same element, and the class selector wins on specificity once Angular's encapsulation attribute is added. You are not fighting the library; you are participating in its API. Naming A consistent scheme makes tokens greppable and lintable: Prefix everything with . It signals "this is library API" and makes it trivial to find every token in use across twenty repositories with one grep. Document them as API Tokens are API, which means Chapter 4's rules apply. Put them in the component's Storybook docs and treat renames as breaking changes: How many tokens per component Enough to cover realistic customisation; not so many that you have re-created the over-configuration trap in CSS. A useful default is background, foreground, border, radius, and padding . Add more when a consumer asks twice. Do not expose internal layout values — is somebody asking for a different component. "But I thought two tiers were enough" Two tiers is the most common setup — primitives and semantics — and it genuinely solves the biggest problem, which is hardcoded hex codes scattered through components. Teams that get that far have already won most of the argument. Adding a third feels like ceremony. The gap shows up the first time a consumer needs a local exception, and that request is guaranteed to arrive. With two tiers, every customisation is a semantic override, and semantic tokens are shared by definition. There is no way to say "this button" — only "everything primary in this subtree". So the consumer has exactly three options, and all of them are bad: 1. Override the semantic token and accept forty unintended changes. 2. Reach in with and couple to an internal class name. 3. Ask the library for a input — which is the over-configuration trap from Chapter 5, arriving through CSS instead of TypeScript. The third tier gives them a fourth option that costs the library nothing. Request: one green approve button Two tiers Three tiers --- --- --- Mechanism available Override Set Elements affected Every primary element in the subtree One button Library change needed No, but the result is wrong No Alternative if it is unacceptable or a new input None needed Library free to change internals Only if nobody pierced it Yes There is a second benefit that is less obvious. Component tokens are the documentation of what is customisable. With two tiers, a consumer facing a button has no idea whether changing its colour is supported; they experiment. With a documented token list, the answer is on the page — and so is the answer to "what is n…