Strata Design System Rework Notes
Reworking a flat, undifferentiated interface into a layered language of five surface levels and eight hue tracks: the styles are still a single CSS file, but every block of content has a place again.
Contents
Jump straight to a section.
Browse the components demo page first, then read this article alongside the layering and split ideas it describes.
Layering and hue
Hierarchy is not decoration, it is structure: five surface levels plus a dedicated inset well layer
The rework started from a very concrete complaint: every block of content on the page looked equally heavy. Cards, tables, quotes and notes all shared the same grey background with a single border, so there was no break point while scrolling and readers could barely tell paragraphs apart by heading size alone. This is the most common side effect of flat design — once hierarchy is deleted, nothing is left to speak for it.
Strata's answer is to turn hierarchy into readable information instead of patching it with decoration. Two things: grade the surfaces, and give each section a hue.
Surfaces are split into five levels — void / base / surface-1 /
surface-2 / surface-3, plus an inset well layer that sits darker than
the page itself. All structure is carried by light and shade plus a 1px hairline, and static panels never take
a shadow — show a border and a shadow at the same time and the edge goes muddy.
Each section in turn owns a hue track, and the hue appears in only three places: the monospace index badge, the hairline at the top of the section, and a soft tint in the background. Adjacent sections never share a background, so every segment has a clear entry and exit while scrolling.
/* Semantic tokens — components never reference raw colour values */html.strata-root { --base: #060b14; --surface-1: #0b111f; --surface-3: #161f33; --line: rgba(255,255,255,.09); --line-strong: rgba(255,255,255,.17); --accent: #3b82f6; /* Accent: blue */} /* All component rules are scoped inside .strata; 0,1,1 outranks the site's global 0,1,0 */.strata .btn { background: var(--accent); color: var(--accent-ink); }
- [*]band treatments6
- [*]section hues8
- [*]surface levels5 + inset
- [*]hairline weights3
- [*]hovercolour swap, no tween
“Flat design isn't about deleting hierarchy, it's about drawing hierarchy more accurately. A hairline is enough — there's no need to add another shadow.”
Component split
30 components, four layers of responsibility, one and the same class-name contract
The work was split along section boundaries into 30 components: base components handle the visuals, interactive components handle behaviour, and all of them expose their configuration through props while following the same class-name contract, so the body styles never collapse.
- Surface layer: Panel / Card / StatCard / GlassTable / ListGroup
- Structure layer: Band / SectionHeading / SpecList / Divider / KeyCap
- Interaction layer: Modal / Toast / Tooltip / Dropdown / Tabs / SearchBox
- Feedback layer: Alert / Progress / Spinner / Skeleton / Empty / StatusIndicator
- Skeleton layer: ArticleShell / ArticlePart / Sidebar / EdgeRail
Interaction runtime
One round of event delegation, everything declared by attributes
No JS has to be written by hand anywhere on the page: opening modals, firing toasts, toggling dropdowns,
copying code, sorting tables — all of it is declared with data-strata-* attributes, and the runtime
does a single round of event delegation on the document. Keyboard semantics are complete — focus trapping in
modals, Esc to close and restore focus, arrow-key roaming in tablists, ↑↓ selection in the command palette.
<!-- Interactions are declared with data-strata-* attributes — no JS on the page --><Button data-strata-open="confirmModal">Open modal</Button><Button data-strata-toast="Saved">Save</Button><CodeBlock code="npm i" /> <!-- The copy button wires itself up --> <!-- Typewriter / number count-up / scroll reveal are attribute-driven as well --><span data-strata-type data-words='["A","B"]'>A</span><span data-strata-count="128">0</span><div class="pg-reveal">Fades in when it enters the viewport</div>
Light and dark theming
Only one set of semantic tokens changes; there is no dark: variant in any component
The theme changes one set of semantic tokens only; there is not a single dark: variant inside any
component. Dark is the default, the choice is written to localStorage, and it is restored by an
inline script placed before the stylesheet — so there is no white flash on refresh. To share a particular theme
directly, just add ?mode=light.
The moment you switch, a 260ms cross-fade is applied to the whole page: it only transitions colour-like properties, so movement animations and the “hover never tweens colour” rule are unaffected.
The whole system compresses down to 2.1kb of CSS (gzip). What really keeps it from going muddy isn't the new components but the decisions that look trivial: three hairline weights, six backgrounds, eight hues — and one rule that refuses to compromise: hover swaps colour, it never animates.