A token-driven, dark-mode-first design system. Vanilla CSS + minimal JS. Reused across every project.
Live demo: https://kiriz.github.io/kiri-ux
Every project hand-rolling its own CSS means hardcoded colors, drift between projects, and reinventing the same components. kiri-ux is the single source of truth for visual and interaction decisions. Add it once, pick a theme, and the hardest UI problems — dark mode, accessible focus rings, sidebar layout, loading/empty states — are already solved.
primitive → semantic → component
hsl(...) --color- .btn references
raw value surface --color-surface
- Primitives (
tokens/primitives/) — raw values. 12-step HSL color scales, an 8-point spacing grid, a 1.25 type scale, sub-atomic shadows. Never referenced directly by components. - Semantic (
tokens/semantic/) — role names.--color-surface,--color-on-surface,--color-primary. This is what components reference. Roles stay constant; only the primitives they point at change per theme. - Components (
components/) —.btn,.card,.alert. Reference only semantic tokens. No hardcoded colors (enforced by CI).
Rotating a single --primary-hue re-tints the entire system because every color flows through the scale.
git submodule add https://github.com/kiriz/kiri-ux site/kiri-ux<link rel="stylesheet" href="kiri-ux/tokens/themes/base.css">
<link rel="stylesheet" href="kiri-ux/tokens/themes/yourproject.css"><!-- optional -->
<link rel="stylesheet" href="kiri-ux/components/index.css">
<script src="kiri-ux/components/interaction.js" defer></script>Pull updates deliberately: git submodule update --remote site/kiri-ux.
<link rel="stylesheet" href="https://kiriz.github.io/kiri-ux/tokens/themes/base.css">
<link rel="stylesheet" href="https://kiriz.github.io/kiri-ux/components/index.css">Copy tokens/themes/_template.css to tokens/themes/yourproject.css:
:root {
--primary-hue: 160; /* teal — the one knob that matters */
--neutral-hue: 200; /* surface warmth */
--scaling: 1; /* density: 0.9 compact, 1.1 comfortable */
--radius-scaling: 1; /* 0 sharp, 1.5 rounded */
}Dark is default. Toggle light with one attribute, no JS:
<html data-theme="light">| Group | Components |
|---|---|
| General | Button, Badge |
| Layout | Container, Stack, Cluster, Auto-grid, Sidebar shell |
| Navigation | Header, Sidebar, Breadcrumb, Tabs |
| Data Entry | Form field, Input, Select, Sort bar, Filter bar |
| Data Display | Card (+ news variant), Confidence bar, Stat box, Data table, Timeline |
| Feedback | Alert, Spinner, Skeleton, Empty state, Toast |
| Interaction | Dropdown, Modal, Accordion |
| Specialized | Code block, Pipeline (numbered trace) |
Each is documented in the demo with "when to use / when NOT to use" and a copyable snippet.
Beyond components, patterns/ documents the decisions:
patterns/layout.md— sidebar vs full-width vs centeredpatterns/navigation.md— header vs sidebar vs breadcrumb vs tabspatterns/data-display.md— cards vs tables vs timelinespatterns/feedback.md— toast vs alert vs empty statepatterns/forms.md— field layout, validation timingpatterns/motion.md— when motion clarifies vs distracts
- Edit tokens/components/patterns.
npx stylelint "**/*.css"+bash scripts/check-hardcoded-colors.shmust pass.- Breaking changes (anything requiring consuming-project updates) are tagged
[BREAKING]inCHANGELOG.mdand bump the major version.
Tags become CDN versions: kiriz.github.io/kiri-ux/v{major}.{minor}/. Major = breaking, minor = additive, patch = fixes. Consuming projects pin to a submodule commit and update deliberately.
Architecture informed by Primer CSS (two-tier tokens, semantic naming), Radix Themes (12-step scales, --scaling), Open Props (sub-atomic shadows), and Ant Design (component taxonomy, motion principles).