Foundation
Theming
style.cssDOM Studio uses css variable design tokens: base tokens paint skins, and matching -fg tokens keep text readable.
Model
Colour and fg pairs
Use the base token when you are painting a background. Use the matching *-fg token when text or icons need to sit on it.
Filled action
bg-primary
text-primary-fg
Quiet panel
bg-secondary
text-secondary-fg or text-fg
Token naming convention
- Bg token
- DOM Studio --primary
- Fg token
- DOM Studio --primary-fg
- Added pairs
- primary, secondary, muted, accent, status
At a glance
Read the theme as product UI
Project dashboard
Example composition using only semantic tokens.
Revenue
GBP 42,860
Quiet panel
Secondary skins group nearby controls without demanding attention.
Review needed
Warning tokens should feel noticeable, not alarming.
Command menu
Editor
Tune CSS variable colours
Primary - light
--primary: oklch(0.205 0 0)
Corners
The base radius that feeds the rounded scale.
Shape preview
Radius is still global because it affects every rounded utility.
Rounded frame
Uses the same radius scale as components.
Skin recipes
These Tailwind-like utilities carry material, border, shadow, blur, and gradient from variables.
Base
skin-base
The page canvas and ordinary application background.
Raised
skin-raised
Cards, panels, calendars, and grouped content.
Floating
skin-floating
Dropdowns, popovers, combobox menus, and context menus.
Dialogs, drawers, command palettes, and action sheets.
Inset
skin-inset
Inputs, textareas, and editable recessed controls.
Control
skin-control
Secondary buttons, quiet triggers, and neutral controls.
Action
skin-action
Primary actions and high-emphasis commands.
Light mode
:root
Canvas
Page background and ordinary text.
Canvas
Page background and ordinary text.
Primary
Primary actions and high emphasis selected states.
Primary
Primary actions and high emphasis selected states.
Secondary
Quiet buttons, subtle panels, inactive controls, and helper UI.
Secondary
Quiet buttons, subtle panels, inactive controls, and helper UI.
Muted
Low-emphasis backgrounds and supporting copy.
Muted
Low-emphasis backgrounds and supporting copy.
Accent
Hover, focus, active rows, and soft selected states.
Accent
Hover, focus, active rows, and soft selected states.
Destructive
Delete, remove, error, and irreversible actions.
Destructive
Delete, remove, error, and irreversible actions.
Success
Saved, complete, connected, and positive confirmation states.
Success
Saved, complete, connected, and positive confirmation states.
Warning
Attention, pending review, expiring, and recoverable risk states.
Warning
Attention, pending review, expiring, and recoverable risk states.
Edges and focus
Borders, input chrome, and keyboard focus rings.
Dark mode
[data-theme="dark"]
Canvas
Page background and ordinary text.
Canvas
Page background and ordinary text.
Primary
Primary actions and high emphasis selected states.
Primary
Primary actions and high emphasis selected states.
Secondary
Quiet buttons, subtle panels, inactive controls, and helper UI.
Secondary
Quiet buttons, subtle panels, inactive controls, and helper UI.
Muted
Low-emphasis backgrounds and supporting copy.
Muted
Low-emphasis backgrounds and supporting copy.
Accent
Hover, focus, active rows, and soft selected states.
Accent
Hover, focus, active rows, and soft selected states.
Destructive
Delete, remove, error, and irreversible actions.
Destructive
Delete, remove, error, and irreversible actions.
Success
Saved, complete, connected, and positive confirmation states.
Success
Saved, complete, connected, and positive confirmation states.
Warning
Attention, pending review, expiring, and recoverable risk states.
Warning
Attention, pending review, expiring, and recoverable risk states.
Edges and focus
Borders, input chrome, and keyboard focus rings.
:root {
--radius: 0.625rem;
--skin-base-bg: var(--background);
--skin-base-fg: var(--fg);
--skin-base-border: transparent;
--skin-base-border-width: 0px;
--skin-base-border-style: solid;
--skin-base-shadow: none;
--skin-base-backdrop: none;
--skin-base-bg-image: none;
--skin-raised-bg: color-mix(in oklch, var(--background) 98.5%, var(--fg));
--skin-raised-fg: var(--fg);
--skin-raised-border: var(--border);
--skin-raised-border-width: 1px;
--skin-raised-border-style: solid;
--skin-raised-shadow: var(--shadow-sm);
--skin-raised-backdrop: none;
--skin-raised-bg-image: linear-gradient(to bottom, color-mix(in oklch, white 7%, transparent), color-mix(in oklch, var(--fg) 1%, transparent));
--skin-floating-bg: color-mix(in oklch, var(--background) 94%, var(--fg));
--skin-floating-fg: var(--fg);
--skin-floating-border: var(--border);
--skin-floating-border-width: 1px;
--skin-floating-border-style: solid;
--skin-floating-shadow: var(--shadow-xl);
--skin-floating-backdrop: blur(16px) saturate(1.08);
--skin-floating-bg-image: none;
--skin-overlay-bg: color-mix(in oklch, var(--background) 95%, var(--fg));
--skin-overlay-fg: var(--fg);
--skin-overlay-border: var(--border);
--skin-overlay-border-width: 1px;
--skin-overlay-border-style: solid;
--skin-overlay-shadow: var(--shadow-2xl);
--skin-overlay-backdrop: blur(20px) saturate(1.12);
--skin-overlay-bg-image: none;
--skin-inset-bg: color-mix(in oklch, var(--background) 98%, var(--fg));
--skin-inset-fg: var(--fg);
--skin-inset-border: var(--input);
--skin-inset-border-width: 1px;
--skin-inset-border-style: solid;
--skin-inset-shadow: inset 0 1px 2px rgb(15 23 42 / 0.04);
--skin-inset-backdrop: none;
--skin-inset-bg-image: none;
--skin-control-bg: var(--secondary);
--skin-control-fg: var(--secondary-fg);
--skin-control-border: var(--border);
--skin-control-border-width: 1px;
--skin-control-border-style: solid;
--skin-control-shadow: var(--shadow-xs);
--skin-control-backdrop: none;
--skin-control-bg-image: none;
--skin-action-bg: var(--primary);
--skin-action-fg: var(--primary-fg);
--skin-action-border: color-mix(in oklch, var(--primary) 80%, var(--border));
--skin-action-border-width: 1px;
--skin-action-border-style: solid;
--skin-action-shadow: var(--shadow-sm);
--skin-action-backdrop: none;
--skin-action-bg-image: linear-gradient(to bottom, color-mix(in oklch, white 10%, transparent), transparent);
}
:root {
--background: oklch(1 0 0);
--fg: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-fg: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-fg: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-fg: oklch(0.5 0 0);
--accent: oklch(0.97 0 0);
--accent-fg: oklch(0.205 0 0);
--destructive: oklch(0.583 0.239 28.476);
--destructive-fg: oklch(0.985 0 0);
--success: oklch(0.632 0.186 147.369);
--success-fg: oklch(0.985 0 0);
--warning: oklch(0.839 0.16 84.07);
--warning-fg: oklch(0.281 0.07 46.31);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.709 0 0);
}
[data-theme="dark"] {
--background: oklch(0.145 0 0);
--fg: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-fg: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-fg: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-fg: oklch(0.709 0 0);
--accent: oklch(0.269 0 0);
--accent-fg: oklch(0.985 0 0);
--destructive: oklch(0.702 0.189 22.228);
--destructive-fg: oklch(0.985 0 0);
--success: oklch(0.702 0.158 160.438);
--success-fg: oklch(0.145 0 0);
--warning: oklch(0.772 0.173 65.367);
--warning-fg: oklch(0.145 0 0);
--border: oklch(0.269 0 0);
--input: oklch(0.321 0 0);
--ring: oklch(0.556 0 0);
}Tokens
Palette and pairs
Background
bg-background text-fg
The app canvas and ordinary page text.
Primary
bg-primary text-primary-fg
Primary actions and high emphasis selected states.
Secondary
bg-secondary text-secondary-fg
Quiet buttons, subtle panels, inactive controls, and helper UI.
Muted
bg-muted text-muted-fg
Low-emphasis backgrounds and supporting copy.
Accent
bg-accent text-accent-fg
Hover, focus, active rows, and soft selected states.
Destructive
bg-destructive text-destructive-fg
Delete, remove, error, and irreversible actions.
Success
bg-success text-success-fg
Saved, complete, connected, and positive confirmation states.
Warning
bg-warning text-warning-fg
Attention, pending review, expiring, and recoverable risk states.
Border
--borderEdges, separators, low-emphasis rings, and component outlines.
border-border ring-border divide-border
Input
--inputInput borders and control tracks that should read as editable.
border-input bg-background
Ring
--ringKeyboard focus, inspector selection, and strong focus affordances.
focus-visible:ring-ring outline-ring
Decision guide
Which token should I use?
| Intent | Utility | Rule of thumb |
|---|---|---|
| Page background | skin-base | Use once at layout level when the canvas should come from the theme recipe. |
| Card or panel | skin-raised | Use for grouped content that needs the standard raised material. |
| Popover or menu | skin-floating | Use for layers attached to a trigger. |
| Dialog or drawer | skin-overlay | Use for modal and app-level overlay panels. |
| Input chrome | skin-inset | Use for recessed editable controls. |
| Primary button | skin-action | Use for high-emphasis commands. |
| Secondary button | skin-control | Use for quiet controls and neutral triggers. |
| Menu item hover | hover:bg-accent hover:text-accent-fg | Use accent for temporary interaction states. |
| Helper copy | text-muted-fg | Use for hints, captions, placeholders, and metadata. |
| Danger action | text-destructive or bg-destructive text-destructive-fg | Text-only for subtle danger, filled for destructive confirmation. |
| Success status | bg-success text-success-fg | Use for positive, completed, or saved states. |
| Warning status | bg-warning text-warning-fg | Use when attention is needed but the action is recoverable. |
| Focus state | focus-visible:ring-ring | Use for keyboard focus, usually with a transparent offset. |
Code
Define and consume tokens
:root {
--background: oklch(1 0 0);
--fg: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-fg: oklch(0.985 0 0);
--success: oklch(0.627 0.194 149.214);
--success-fg: oklch(0.985 0 0);
--warning: oklch(0.84 0.16 84);
--warning-fg: oklch(0.28 0.07 46);
--skin-raised-bg: color-mix(in oklch, var(--background) 98.5%, var(--fg));
--skin-raised-fg: var(--fg);
--skin-raised-shadow: var(--shadow-sm);
--skin-raised-bg-image: linear-gradient(to bottom, color-mix(in oklch, white 7%, transparent), color-mix(in oklch, var(--fg) 1%, transparent));
--skin-floating-bg: color-mix(in oklch, var(--background) 94%, var(--fg));
--skin-floating-shadow: 0 24px 64px -26px rgb(15 23 42 / 0.42);
--skin-floating-backdrop: blur(20px) saturate(1.16);
}<button class="skin-action rounded-full px-4 py-2">
Save changes
</button>
<div class="skin-raised rounded-2xl p-4">
<p class="text-sm text-muted-fg">Use secondary text inside a card.</p>
</div>
<div class="skin-floating rounded-2xl p-2">
<button class="rounded-xl px-3 py-2 hover:bg-accent hover:text-accent-fg">
Open project
</button>
</div>