Docs
Styling & Theming
The DS resolves every color, space, and radius through a --yl-* CSS custom
property. That's what lets primitives render on the server and lets a theme
switch be one attribute write. This guide covers how the stylesheets are shipped
in 0.2.0 and the one rule that trips people up: the 10px root.
#Two required sheets, the rest opt-in
In 0.2.0, component styles moved out of themeCss() and into shipped files.
Always import the tokens and the base layer; add a component's sheet when you
render it:
import "@yoltra/ds/styles/tokens.css"; // --yl-* variables, light + dark
import "@yoltra/ds/styles/base.css"; // html 62.5% root, .yl-root, .yl-container, .yl-visually-hidden
import "@yoltra/ds/styles/button.css";
import "@yoltra/ds/styles/modal.css"; // Dialog + DrawerThis is deliberate. The JavaScript tree-shakes, but a single stylesheet carrying
every component's rules cannot — it becomes a cost every app pays regardless of
what it renders. For a docs site or a prototype, @yoltra/ds/styles/all.css
carries everything in one import.
Migrating from 0.1.0? themeCss() used to emit variables and every
component's rules. It now emits variables only. Import the component sheets
(or all.css) or your components will render unstyled.
#themeCss() — for a server render
themeCss() is still exported and emits the same custom properties, for when you
need them inlined before first paint rather than linked:
<style dangerouslySetInnerHTML={{ __html: themeCss() }} />It gives you the variables only — pair it with the component sheets (or link
tokens.css instead). A file-based app doesn't need it at all.
#1rem is 10px
base.css sets html { font-size: 62.5% }, making the root 10px so every length
reads as its pixel value over ten — 1.6rem is 16px, 0.4rem is 4px. Tokens are
authored in pixels (because spacing[4] being 16 beats 1.6) and only the
emitted value carries the unit. rem rather than px so a reader's font-size
preference still scales the interface.
Three things follow, and they're easy to get wrong:
- Set your body font-size.
.yl-rootcarries no font-size, so inherited text resolves against the 10px root. Pin a base (e.g.body { font-size: 1.6rem }). - The root declaration is global. It affects the whole document. An app that
can't accept that imports
@yoltra/ds/styles/base-no-root.cssand sets its own root — at which point every--yl-*length is relative to whatever it chooses. - Breakpoints and hairlines stay in pixels. A
rembreakpoint resolves against the initial root, not the 62.5% one, so it would silently be 1.6× its value; a 1px border should be 1px.
#Theming
Theming is data-theme on the document root — "light" or "dark":
import { ThemeProvider, useTheme, applyTheme } from "@yoltra/ds/client";ThemeProvider holds the theme and reflects it onto the root; useTheme() reads
and sets it; applyTheme("dark") writes the attribute directly (handy in a
pre-hydration script to avoid a flash of the wrong theme). Consumers that own
their state — like this site, which drives the theme through a Yoltra store — skip
the provider and set data-theme themselves. The DOM contract is identical.
See the API reference for foundationTokens, lightTheme /
darkTheme, and every --yl-* name.