L0
Types
Shared TypeScript surface — every layer above speaks this contract.
Headless · Svelte 5 · Layered
Kumiki — 組木 — is a deeply accessible UI primitive system for Svelte 5. Five composable layers, twenty components, ten locales. No CSS opinions, no runtime decisions you can’t re-make.
pnpm add @kumiki/components/ 02 — Architecture
Each component lives at exactly one layer. Pick the layer that matches your control needs — and ship the bytes for that layer only.
L0
Shared TypeScript surface — every layer above speaks this contract.
L1
Framework-agnostic helpers — focus trap, dismissable, IDs, locale.
L2
Pure-TS finite state machines. Inspectable JSON. ~1 KB runtime.
L3
Svelte 5 {@attach} factories. ARIA + data-state on real DOM.
L4
Compound primitives. <Toggle.Root>, <Combobox.Input>, the lot.
L5
Layer 5 preview — copy-pasteable styled variants. Ships at 0.x preview.
/ 03 — Discipline
1.5–4.5 KB
Every component subpath has a brotli budget. Going over fails CI. Toggle ships in 1.5 KB; Combobox in 4.5 KB.
WCAG 2.2 AA
macOS-VoiceOver and Windows-NVDA via Guidepup, on a schedule. Axe + APG keyboard tests on every PR.
10 locales
No mega-bundle. @kumiki/locale/<lang> at ≤ 1 KB each. RTL inversion lives in the machines.
toJSON()
Each machine.toJSON() exports a Stately-viewable config. Inspect any FSM in stately.ai/viz.
/ 04 — In code
<script lang="ts">
import Toggle from '@kumiki/components/toggle';
let pressed = $state(false);
</script>
<Toggle.Root bind:pressed aria-label="Mute">
{pressed ? 'Muted' : 'On'}
</Toggle.Root>