@dorsk/tsumikit
Svelte 5 UI components styled with plain CSS variables: 31 themes, WCAG AA contrast, no runtime dependencies.
Every colour, space, radius and size is a CSS custom property: a theme is one block of variables, a component is restyled with style="--btn-bg: …". Interactive parts use <dialog>, the Popover API and native form controls; a design lint and design principles ship in the package.
Live demo with every component and prop
Install
npm i @dorsk/tsumikit
Peer: svelte@^5.0.0. Inter font bundled.
Quick start
<script lang="ts">
import '@dorsk/tsumikit/styles/app.css';
import { Button, Field, Input, Toaster, toasts } from '@dorsk/tsumikit';
let name = $state('');
</script>
<Field label="Workspace name" for="name">
<Input id="name" bind:value={name} />
</Field>
<Button variant="primary" onclick={() => toasts.ok(`Saved ${name}`)}>Save</Button>
<Toaster />
Import the stylesheet once at the app root. Pressing Save shows an ok toast.
Start a new project
Copy examples/starter and replace "file:../.." with a version. Contents: examples/starter/README.md.
Upgrading from 0.82 or older: docs/MIGRATION-0.83.md (and 0.82).
Theming
31 themes, all tested for WCAG AA contrast. <ThemePicker /> persists the choice in localStorage; auto follows prefers-color-scheme.
import { theme } from '@dorsk/tsumikit';
theme.register({ id: 'acme', label: 'Acme', mode: 'dark' });
theme.setDefault('acme');
/* brand.css, imported after the kit stylesheet */
[data-theme='acme'] {
--c-bg: #2a2a2a;
--c-accent: #5ac8c8;
/* …the rest of the 19 --c-* palette tokens, shadows and --mach-* pairs */
}
<Button style="--btn-bg: var(--c-violet); --btn-fg: #fff; --btn-radius: 0">Ship</Button>
Theme contract, looks, stylesheets and typeface: docs/theming.md. Per-component custom properties and test ids: docs/styling.md.
Components
Layers: tokens.css, atoms (the only raw <button>/<input>/<select>), molecules, layouts. Each reaches one layer down (docs/design.md). Props, aria-* included, spread onto the underlying element.
| Layer | Components |
|---|---|
| Atoms | Text, Heading, Button, Input, Textarea, Select, Switch, Checkbox, Slider, Gauge, Avatar, Card, Badge, Link, Icon |
| Molecules | Field, Modal, Popover, Menu, Tabs, FilterChips, Combobox, Disclosure, Accordion, Toaster, ThemePicker, Drawer, SplitButton, SortableList |
| Organisms | DataTable, ConversationPanel, ConversationFeed, FilterSearchBar |
| Layouts | AppShell, NavBar, MasterDetail, Container, Stack, Cluster, AutoGrid |
| Mobile and media | TabBar, SwipeRow, PullToRefresh, SeekSlider, VolumeSlider |
| Stores and helpers | theme, toasts, fontScale, autoresize, copyToClipboard |
| Guide | Covers |
|---|---|
| Patterns | loading, reserving the final box, row actions and selection, choice controls, undo over confirm, URL state, breakpoints |
| Layout and sizing | container queries, rem sizing, control heights, 44px hit areas |
| Guardrails | tsumikit-lint CLI, dev-mode warnings |
| Sound | opt-in UI sounds |
| Accessibility | ARIA patterns, platform features |
| Design principles | 30 principles, each with a check |
Limitations
- Svelte 5 only.
- No bundled syntax highlighter:
CodeBlocktakes ahighlightcallback (details). - Internal class names (
.btn) anddata-tsumarkers are private and may change in any release. Style through the published custom properties, not:global(). - Pre-1.0: minor releases can change defaults. Migration notes are in
docs/.
Development
git clone https://github.com/DorskFR/tsumikit && cd tsumikit
npm install
npm run dev # showcase at the printed URL (+ /shell for the AppShell demo)
npm test # contract tests (node --test)
npm run lint # biome
npm run check # svelte-check
npm run build # prerendered static site in /build
npm run package # publishable library in /dist (+ publint)
Hooks (lefthook, via prepare): Biome on commit, svelte-check on push. A v* tag publishes to npm through GitHub Actions trusted publishing.