Neutral ramps
The data-neutral attribute on <html> (or any subtree) swaps the
neutral ramp — the greys behind every surface, border, muted
background, secondary button, and body text — without touching the
accent colour. Five ramps ship out of the box, each tuned for both
light and dark.
data-neutral is orthogonal to data-color
(accent), data-theme (light / dark), and
data-density. Set them on the
same ancestor and they all cascade together — e.g. an indigo accent on a
slate neutral in dark mode is data-color="indigo" data-neutral="slate" data-theme="dark".
data-neutral value | Character | Light page bg / border | Dark surface |
|---|---|---|---|
(none) / gray | Default neutral | #f9fafb / #d0d5dd | #1f2937 |
slate | Cool, blue-tinted | #f8fafc / #cbd5e1 | #1e293b |
zinc | Cool, desaturated | #fafafa / #d4d4d8 | #27272a |
neutral | Pure grey | #fafafa / #d4d4d4 | #262626 |
stone | Warm, brown-tinted | #fafaf9 / #d6d3d1 | #292524 |
In light mode the card surface stays white for every ramp (only the page background, borders, muted fills, secondary buttons, and text shift) — matching the default. In dark mode the surface itself re-tints to the ramp’s 800 shade. Toggle the theme switch in the header to see the dark variant of each row below.
Live preview
Section titled “Live preview”Each panel below carries a different data-neutral value. The outer
panel uses the ramp’s page background; the inner card is a surface.
Applying it to your page
Section titled “Applying it to your page”Site-wide, set it on <html>:
<html data-neutral="slate">…</html>Per-section override:
<section data-neutral="stone">…</section>Like the other axes, it works on a subtree because each ramp block
re-declares the affected component variables with concrete values (no
frozen var() inheritance) — see
how the cascade works.
What changes
Section titled “What changes”Each non-default ramp overrides these semantic keys (light in
neutral.<ramp>.tokens.json, dark in neutral.<ramp>.dark.tokens.json):
--hc-color-bg --hc-color-text --hc-color-text-muted--hc-color-border --hc-color-muted-bg --hc-color-surface (dark only)--hc-color-action-secondary-* --hc-color-status-neutral-*These cascade into every component’s --hc-{component}-* surface / text /
border variables. The build re-emits the affected leaves inside
[data-neutral="<ramp>"] (light) and
[data-theme="dark"][data-neutral="<ramp>"] (dark) blocks.
Deliberately not affected:
- Accent (
action.primary, focus ring) — owned bydata-color. - Semantic
info/success/warning/error— fixed status palette. - Control sizing — owned by
data-density.
Related
Section titled “Related”- Color themes — the accent axis. Pair it with a neutral.
- Theme builder — its Full theme mode bakes an accent + neutral together.
- Color palette — the primitive ramps these resolve to.
- Density — orthogonal sizing axis.