Styles
Components in this section are headless — they ship with no CSS. The elements-kit/ui/styles layer is an optional theme package on top. Skip it entirely and style with your own system, or import only the pieces you want.
Install
import "elements-kit/ui/styles/theme.css";import "elements-kit/ui/styles/material.css";import "elements-kit/ui/styles/scaling.css";import "elements-kit/ui/styles/radius.css";import "elements-kit/ui/styles/space.css";import "elements-kit/ui/styles/shadow.css";import "elements-kit/ui/styles/typography.css";import "elements-kit/ui/styles/cursor.css";import "elements-kit/ui/styles/unset.css";
// One gray scale (pick one)import "elements-kit/ui/styles/neutral/slate.css";// One accent scale (any color)import "elements-kit/ui/styles/accent/green.css";import "elements-kit/ui/styles/typography.css";import "elements-kit/ui/styles/radius.css";import "elements-kit/ui/styles/palette/blue.css";Theming via data attributes
Switches are data-* attributes on a root container — not classes you toggle, not a JS provider.
<body class="dark" data-radius="medium" data-scaling="md" data-material-background="translucent" data-accent="iris" data-neutral="slate"> ...</body>| Attribute | Values |
|---|---|
data-radius | none · small · medium · large · pill |
data-scaling | xs · sm · md · lg · xl |
data-material-background | solid · translucent |
data-accent | accent name — see accent list |
data-neutral | gray · mauve · olive · sage · sand · slate |
Light & dark
Color tokens flip when the container has .dark or .dark-theme. .light / .light-theme opt back in.
<html class="dark">...</html>Pair with createMediaQuery to follow the OS preference:
import { createMediaQuery } from "elements-kit/utilities/media-query";import { effect } from "elements-kit/signals";
const prefersDark = createMediaQuery("(prefers-color-scheme: dark)");effect(() => { document.documentElement.classList.toggle("dark", prefersDark());});Token reference
Override any token by re-declaring on :root or any container.
Color
Semantic — read these in your component CSS:
--color-background--color-overlay--color-material-solid,--color-material-translucent,--color-material,--backdrop-filter-material--color-surface--color-transparent--focus-1..--focus-12,--focus-a1..--focus-a12(alias of the active color)
Scales:
--neutral-1..--neutral-12plus--neutral-a1..--neutral-a12— the active neutral (set byneutral/<scale>.cssordata-neutral).--accent-1..--accent-12plus--accent-a1..--accent-a12— the active accent (set byaccent/<color>.cssordata-accent).--<color>-1..--<color>-12plus alpha — raw palette scales frompalette/<color>.css, e.g.--blue-9.--black-a1..--black-a12and--white-a1..--white-a12— alpha-on-color scales frompalette/black-alpha.css/palette/white-alpha.css(auto-imported bytheme.css).
Typography
--font-size-1..--font-size-9, --line-height-1..9, --letter-spacing-1..9, plus weights --font-weight-{light,regular,medium,bold}. Per-element families and overrides (--heading-*, --code-*, --strong-*, --em-*, --quote-*, --tab-*) live in typography.css.
Radius
--radius-1..--radius-6, --radius-pill, --radius-thumb. All scale with --radius-factor (driven by data-radius) and --scaling.
Spacing
--space-1 (4px) · --space-2 (8px) · --space-3 (12px) · --space-4 (16px) · --space-5 (24px) · --space-6 (32px) · --space-7 (40px) · --space-8 (48px) · --space-9 (64px). Each multiplied by --scaling.
Shadow
--shadow-1..--shadow-6. Light/dark variants ship out of the box, with a color-mix(in oklab, ...) upgrade for browsers that support it.
Cursor
--cursor-button, --cursor-checkbox, --cursor-link, --cursor-disabled, --cursor-menu-item, --cursor-radio, --cursor-slider-thumb, --cursor-slider-thumb-active, --cursor-switch. Defaults are platform-native; override per-element if you want a pointer button.
Unset native styles
Native form and text elements — <button>, <input>, <a>, <h1>–<h6>, lists, tables, <svg>, <img> — ship with browser defaults that bleed through component styles (gray button background, default font, list bullets, etc.). Apply class="unset" from unset.css to neutralise them in one line:
<button class="unset x-button" data-variant="solid" data-size="2"> Click me</button>unset uses :where(...) everywhere so it has zero specificity — your component classes (.x-button, .x-checkbox, …) and your own overrides always win.
Composite components in this kit (Button, future Checkbox, Switch, Listbox…) all rely on it. If you skip the import, native button rendering will leak through .x-button styling.
Customization
Override any token at any level. Container-scoped overrides win over :root:
.brand-card { --color-material-solid: var(--accent-2); --radius-3: var(--radius-5); background: var(--color-material); border-radius: var(--radius-3); padding: var(--space-4);}To swap the active accent, import a different accent/<color>.css:
// Replace this …import "elements-kit/ui/styles/accent/green.css";// … with this.import "elements-kit/ui/styles/accent/iris.css";Available accents: amber, blue, bronze, brown, crimson, cyan, gold, grass, green, indigo, iris, jade, lime, mint, orange, pink, plum, purple, red, ruby, sky, teal, tomato, violet, yellow. Plus semantic aliases that point at the active neutral or a fixed hue: neutral, success, error, warning, info.
Available neutral scales (pick one): gray, mauve, olive, sage, sand, slate.