theme.register() and ships its own [data-theme] block. Foundations
Typography
Heading level 1
Heading level 2
Heading level 3
Heading level 4
Body — the default reading text. Label — form labels & field captions. Caption — small meta text. Code — monospace inline.
default muted faint accent success warn danger
normal medium semibold bold
numeric 1234.50% default 1234.50%
eyebrow italic nowrap text uppercase leading none scale=false 13px
Font-scale slider vs a pinned run — only the first line follows the picker: size="lg" scales with --fs-scale size="lg" scale=false stays pinned
measure="40ch" — a paragraph capped at forty characters wide so long lines stay readable. Truncated heading that runs past its container
Theme tokens
--bg
--bg-elevated
--bg-elevated-2
--surface
--border
--border-strong
--text
--text-muted
--text-faint
--accent
--link
--ok
--warn
--danger
--info
Text scaling opt-in
Optional in-app text-size control (drives
--fs-scale, text tokens only).
Most apps should rely on browser zoom and the user's OS/browser font-size instead —
the kit is rem-based and never resets the root size, so both are respected
out of the box. Reach for this only in reading-dense apps (chat, docs) that want to grow
body text while keeping chrome compact.Layout
Layout: Stack · Cluster · AutoGrid
Cluster — wraps, never overflows: AutoGrid — columns adapt to available width (resize the window): AutoGrid — capped column width (max), left-packed instead of stretching:
alpha beta gamma delta epsilon zeta
Cluster stackAt="md" — buttons stack full-width when the cluster is under 40rem: Cell 1
Cell 2
Cell 3
Cell 4
Cell 5
Cell 6
Fixed 1
Fixed 2
Fixed 3
Card
Static card
An elevated surface with token-driven padding, border and radius.Stacked card
Looks like a pile — two layers peek out bottom-right.Stacked (info)
Back layers tinted with the info/blue hue.tone info
tone ok
tone warn
tone danger
tone attention
Interactive card
Enter/Space activate; the nested button stays independent.maxWidth 22rem
Fills its row up to the cap.MasterDetail
Two columns above its own 48rem breakpoint; below it one pane at a time with a sticky back
header. Drive Same component boxed at 22rem — the mobile regime on desktop:
selected from the URL to make each pane a route. Alice
Alice
Detail pane for Alice.Nothing selected
Pick someone on the left.
Actions
Button
as="a" / as="button" keep the same chrome and focus ring: Hit area — hitArea="compact" drops the 44px touch slab (outlined box shows the real hit box on touch): npm i @dorsk/tsumikit
Icon & IconButton
All registry glyphs (sized at 1em — they scale with text):
back
arrow-right
arrow-up
arrow-down
chevron-up
chevron-down
chevron-left
chevron-right
menu
more
external
log-out
plus
minus
check
x
search
filter
copy
edit
trash
save
download
upload
send
share
retry
settings
play
pause
stop
music
tv
film
disc
file
file-text
folder
archive
image
markdown
list
grid
link
unlink
text-cursor
tag
bookmark
star
heart
fork
live
eye
eye-off
lock
unlock
bell
mail
calendar
clock
home
user
users
sun
moon
loader
info
warning
help
check-circle
x-circle
alert-circle
Toggle · OptionButton · SelectButton
SelectButton (native select over a glyph button): selected: a
SegmentedControl
selected: all
view: grid
scope: album
Forms
Form atoms & Field
Helper text below the control.
This field is required.
Ctrl K ⇧ ↵ Ctrl Alt Esc ↑
On
Checkbox & RadioGroup
Fieldset
Drag a card between pools (HTML5 DnD); buttons are the keyboard path.
FileButton & Dropzone
native picker, keyboard-focusable
Drop files here or click to browse
overlay mode — wraps content, drop UI shows only while dragging a file over it Drawer-like surface
Buttons and content stay clickable. Drag a file anywhere over this card.Data display
Badge · Link · Dot
neutral ok warn danger info
~/path/to/file removable typescript
uppercase stable
soft ok warn danger 3
accent muted violet color dot icon text · 12:34
xs 8 128 a very long account name that clips
active stale dead hibernated custom ring
Metric · StatTile
Tracks
1284
Size
42.7 GB
Quality
FLAC
lossless · 16-bit
Added
37 this week
+12% vs last week
Surface variants — tiles (via Metric) and panels (via Card) opt into the same theme-aware shade by prop, no
:global override: Base
base
Raised
raised
Sunken
sunken
surface base
surface raised
surface sunken
SectionHeader · KeyValue · LoadMore
Recent sessions
12 last 24hGroup rows render here while open.
Failed
2 live
sakura
7Host
sakura- Running
- 3
- Queued
- 0
- Image
- cctui-worker:0.7.3 pulled 2h ago
- Load
- 1.42
- Tokens
- 128000
- Cost
- $0.42
Failed to load
No more items
DataTable generic <T>
| Name | Role | Status |
|---|---|---|
| api-gateway | service | ok |
| worker-02 | worker | warn |
| cache-01 | cache | danger |
layout="fixed" + truncate, hideBelow on the role column, rowTone accent bar, hover-revealed rowActions, size="sm". | Role | Status | Actions | |
|---|---|---|---|
| api-gateway | service | ok | |
| worker-02 | worker | warn | |
| cache-01 | cache | danger |
responsive="stack" in a 22rem-wide box: rows become cards via Column.role (title / detail / meta / hidden), actions stay on the title line. | Name | Role | Status | Id | Actions |
|---|---|---|---|---|
| api-gateway | service | ok | 1 | |
| worker-02 | worker | warn | 2 | |
| cache-01 | cache | danger | 3 |
stackBelow="30rem": it stays tabular in this 34rem box and stacks
once the box drops under 30rem. | Name | Role | Status | Id |
|---|---|---|---|
| api-gateway | service | ok | 1 |
| worker-02 | worker | warn | 2 |
| cache-01 | cache | danger | 3 |
FilterSearchBar organism
YouTrack-style structured search. Typerole:worker, status=ok, or
free text — drive it from the dropdown or type the query language by hand. The bar owns the
query (emits an AST); the host runs it and renders results. | Name | Role | Status |
|---|---|---|
| api-gateway | service | ok |
| worker-02 | worker | warn |
| cache-01 | cache | danger |
SELECT * FROM nodes
WHERE TRUE;FilterInput is the headless primitive underneath — same schema-driven dropdown, but
single-field with no below-bar chips. Its inline snippet renders custom nodes inside
the bar (here, a badge per parsed filter): size="sm" shape="pill" surface="sunken" with hotkey="/" — press / anywhere outside a field to focus it. Timestamp subdued · click for UTC / epoch / zone
Renders an instant in one of six modes (date, time, datetime, relative, iso, short-iso), subdued
by default. The
date/time/datetime modes follow
the viewer's zone unless you pass utc. Click it for a read-only popover
with the same instant as UTC, relative, your time zone and the unix epoch. Opt into selectable to let viewers switch the inline mode. datetime: date: date (utc): iso: short-iso: time: relative: mono: selectable: no popover:
GitRef branch · PR · ±diff
Branch chip, pull-request link and +/− diff stats in one inline row; every part is
optional. The PR state picks its tone (open ok, merged accent, closed danger, draft
muted).
collapse="auto" keeps only the glyphs when the nearest .cq container is narrower than 18rem; glyph forces it. branch: feat/wave-1-new-components-with-a-long-name pr: DorskFR/tsumikit#77 all three: fix/resizable-panel #78 +128 −42 glyph: fix/resizable-panel DorskFR/tsumikit#79 +3 −1
WorkingDir fish-style · degrades with width
Drag the handle: ancestors abbreviate one at a time left to right, then only the leaf
stays, then the leaf ellipsises down to
minLeaf chars. The full path is always
in the tooltip. Truncate char-count · hover reveal
Character-count truncation (the counterpart to
<Text truncate>'s CSS
ellipsis). Hover or focus a truncated value to reveal the full text. middle: 0x71C765…6d8976F
0x71C7656EC7ab88b098defB751B7401B5f6d8976F
end: a-very-long-resourc… a-very-long-resource-identifier-that-keeps-going
start: …/14/request-trace.log /srv/app/var/logs/2026/06/14/request-trace.log
fits (no tooltip): shortCodeBlock BYO highlighter
// install and use
import { Button, theme } from '@dorsk/tsumikit';
function greet(name) {
return `Hello, ${name}!`;
}git clone …
npm install
npm run devFeedback
EmptyState
No results
No albums match your filters. Try broadening the search or clearing filters.
Your library is empty
Add an artist or album to start building your collection.
Nothing here yet
This section hasn't been set up.
Loading sessions…
No results
Try a different query.
Skeleton:
Callout
Auto-search runs in the background and links matches as it goes.
Linked
12 releases matched and were linked to this collection.
Some matches need review
3 releases had several candidates and were left unlinked.
Search failed
The provider returned 503. Try again in a minute.
Searching MusicBrainz for 48 releases…
Narrow container
Wraps its body and actions instead of overflowing.
Toasts
Progress
- conforming 412
- nonconforming 12
- blocked 0
- done 300
- skipped 120
Gauge
🍃
CapBar
Overlays
Tooltip
Tooltips appear on hover and keyboard focus, dismiss with Escape.
Also works on icon buttons.
- service
- api-gateway
- region
- ap-northeast-1
- build
7f3c9e2
Modal
Accessible dialog in the native top layer — Escape to close, click-outside to close, focus
trapped inside and restored to the trigger on close. Drag the right edge to resize (persisted).
ConfirmModal
Drawer
Side panel on the native
<dialog>: Escape, scrim click and the close
button close it; focus is trapped; body scroll is locked. A nav snippet
becomes a 150px page column beside the content on wide viewports and a horizontal strip
above it under 48rem, where the panel goes full-screen.