Theme contract
Every theme sets the same typed list of variables, so components can take every stylistic decision from the theme and never hard-code a look.
Why a contract
THEME_VARIABLES lists the keys every theme must define, and the ThemeDefinition type enforces it: a theme with a missing key does not compile. That keeps
all five built-in themes interchangeable and tells you exactly what a custom theme can control.
Variables
Values are live for monolith-light.
| Variable | Controls | Value |
|---|---|---|
--sv-font-display | Family for headings and large figures. | 'Geist Variable', system-ui, sans-serif |
--sv-font-ui | Family for interface text: labels, buttons, body copy. | 'Geist Variable', system-ui, sans-serif |
--sv-font-data | Family for tabular data and code. | 'Geist Mono Variable', ui-monospace, monospace |
--sv-weight-display | Weight of display text. | 600 |
--sv-tracking-display | Letter spacing of display text. | -0.035em |
--sv-label-size | Size of small labels and table headers. | 0.7862rem |
--sv-label-transform | Casing of small labels (none or uppercase). | none |
--sv-label-tracking | Letter spacing of small labels. | 0 |
--sv-button-transform | Casing of button text. | none |
--sv-button-tracking | Letter spacing of button text. | 0 |
--sv-radius-sm | Small radius: small parts such as skeleton lines and stepper buttons. | 5px |
--sv-radius-md | Control radius: buttons, one-line fields, segmented controls, navigation rows. It may be a pill, so a box that grows with its content (a textarea, an alert) takes the smaller of radius-md and radius-lg. | 8px |
--sv-radius-lg | Surface radius: cards, and the most a box that grows with its content takes. | 13px |
--sv-radius-xl | Radius of large surfaces: dialogs, sheets. | 21px |
--sv-radius-full | Radius of round things: avatars, chips, badges, progress bars. | 999px |
--sv-surface-alpha | Opacity of surfaces; below 100% gives frosted panels. | 100% |
--sv-surface-blur | Backdrop blur behind translucent surfaces. | 0px |
--sv-backdrop | Decorative image behind the page or a scope (gradients), or none. | none |
--sv-ornament | Colour of decorative hairlines on surfaces, or transparent. | transparent |
--sv-bevel | Colour of the 1px highlight on the top edge of raised surfaces. | oklch(1 0 0 / 0) |
--sv-shadow | Elevation shadow of raised surfaces. | 0 1px 2px oklch(0.2 0.01 260 / 0.06), 0 13px 34px -21px oklch(0.2 0.01 260 / 0.24) |
--sv-ease | Easing curve for every transition. | cubic-bezier(0.236, 0, 0, 1) |
--sv-duration-fast | Duration of small state changes (hover, press). | 144ms |
--sv-duration-normal | Duration of most transitions. | 233ms |
--sv-duration-slow | Duration of larger movements (thumbs, panels). | 377ms |
Using the variables
Your own components can follow the active theme the same way Sveltier's do:
.my-card {
border-radius: var(--sv-radius-xl);
font-family: var(--sv-font-ui);
box-shadow: inset 0 1px 0 var(--sv-bevel), var(--sv-shadow);
transition: transform var(--sv-duration-normal) var(--sv-ease);
}
.my-card h2 {
font: var(--sv-weight-display) var(--sv-text-title) / var(--sv-leading-snug)
var(--sv-font-display);
letter-spacing: var(--sv-tracking-display);
}Motion and reduced motion
Themes set their own easing and durations. When the user asks for reduced motion, the base stylesheet collapses all three durations to near zero from a later cascade layer, so it wins over every theme without you doing anything.