The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Define a global property | :root { --color-accent: #0f766e; } | View examples |
| Use a custom property | .link { color: var(--color-accent); } | View examples |
| Provide a fallback | .card { color: var(--card-text, #111827); } | View examples |
| Chain fallbacks | .card {
color: var(--card-text, var(--color-text, #111827));
} | View examples |
| Allow an empty fallback | .icon::after { content: var(--icon-label,); } | View examples |
| Set a component default | .button {
--button-bg: #334155;
background: var(--button-bg);
} | View examples |
| Override a component token | .button--primary { --button-bg: #0f766e; } | View examples |
| Use an inherited token | .button__icon { fill: var(--button-bg); } | View examples |
| Calculate from a token | .stack { gap: calc(var(--space-unit) * 3); } | View examples |
| Compose several tokens | .panel {
box-shadow:
var(--shadow-x) var(--shadow-y) var(--shadow-blur) #0003;
} | View examples |
| Override a dark theme | [data-theme="dark"] {
--surface: #111827;
--text: #f8fafc;
} | View examples |
| Seed a preferred theme | @media (prefers-color-scheme: dark) {
:root { --surface: #111827; --text: #f8fafc; };
} | View examples |
| Register a typed property | @property --progress {
syntax: "<percentage>";
inherits: false;
initial-value: 0%;
} | View examples |
| Animate a registered property | .meter { transition: --progress 300ms ease; } | View examples |
| Respect name casing | :root { --brand: teal; --Brand: navy; } | View examples |
Custom properties store reusable CSS token streams and participate in the cascade. Define semantic values at the broadest useful scope, override them near components or themes, provide fallbacks at consumption points, and remember that unregistered custom properties inherit and are not type-checked by default.
Step by step
Detailed examples
Define semantic values and consume them with var
A custom-property name begins with two hyphens and its value is stored as a CSS token stream. :root is useful for site-wide tokens, but global definitions should describe purpose rather than a particular component. var performs substitution only when another property is computed.
:root { --color-accent: #0f766e; }
.link { color: var(--color-accent); text-decoration-color: var(--color-accent); } Provide fallbacks where values are consumed
The second var argument is used when the referenced custom property is missing or resolves to the guaranteed-invalid value. A nested var creates a fallback chain, and everything after the first comma belongs to the fallback, including additional commas. A fallback does not repair a value that is valid custom-property syntax but invalid for the consuming property in every situation.
.card { color: var(--card-text, var(--color-text, #111827)); }
.icon::after { content: var(--icon-label,); } Override tokens through the cascade
Unregistered custom properties inherit by default. Define a component default on the component root, override it with normal selectors, and let descendants consume the resulting value. Specificity and source order decide which declaration wins before var substitution occurs.
.button { --button-bg: #334155; background: var(--button-bg); color: white; }
.button--primary { --button-bg: #0f766e; }
.button__icon { fill: var(--button-bg); } Compose values and calculations
Custom properties can hold complete values or fragments used by calc and larger declarations. Keep units on the token when it represents a length, or store a unitless multiplier only when every consumer deliberately supplies compatible units. Invalid substitutions invalidate the consuming declaration at computed-value time.
:root { --space-unit: .25rem; --shadow-x: 0; --shadow-y: .5rem; --shadow-blur: 1rem; }
.stack { gap: calc(var(--space-unit) * 3); }
.panel { box-shadow: var(--shadow-x) var(--shadow-y) var(--shadow-blur) #0003; } Build themes from semantic tokens
Theme tokens should describe roles such as surface and text rather than literal colors. An attribute override supports an explicit application theme, while a preference query can seed defaults. Verify contrast in every token combination and set color-scheme when native controls should follow the theme.
:root { --surface: white; --text: #111827; color-scheme: light dark; }
[data-theme="dark"] { --surface: #111827; --text: #f8fafc; }
@media (prefers-color-scheme: dark) { :root { --surface: #111827; --text: #f8fafc; } }
body { background: var(--surface); color: var(--text); } Register type, inheritance, and initial value
The @property rule gives a custom property a syntax, inheritance behavior, and initial value. Registration allows type-aware interpolation and rejects values that do not match the declared grammar. Keep a normal fallback design for older environments when support requirements demand it.
@property --progress {
syntax: "<percentage>";
inherits: false;
initial-value: 0%;
}
.meter { --progress: 25%; transition: --progress 300ms ease; background: linear-gradient(90deg, teal var(--progress), #cbd5e1 0); } Avoid cycles and name mismatches
Custom-property names are case-sensitive, and a dependency cycle makes every property in the cycle invalid. Keep naming consistent, avoid chains that refer back to themselves, and inspect computed styles when a consuming declaration disappears unexpectedly.
:root {
--brand: teal;
--Brand: navy;
--a: var(--b);
--b: var(--a);
}
.example { color: var(--brand); border-color: var(--Brand); } Note: Do not consume --a or --b without a fallback; their cycle makes both values invalid.
Local code tester
Try scoped design tokens
Edit the custom properties and component overrides locally to see inheritance, fallbacks, calculations, and themes.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



