Vital UI
Data & logic helpers
Components are half of a UI. These helpers cover the other half — lists, forms, dialogs, async calls, formatting — so the code around the components stays short, typed and free of the usual bugs. Everything ships from the same barrel.
view.visible, bind view.query, never destructure. They work inside a component or at module level as a
shared store, and none of them uses an $effect. The pages under /demo/pages are built entirely on them.createCollection
A keyed reactive list: get, add, update, remove, count and sum without a single find(x => x.id === id).
createOverlay
One object for a Dialog or Drawer and the thing it is about. bind:open keeps it in sync when the user closes with Escape or the backdrop.
createForm + validation rules
Values, errors and touched state in one place. Errors only show after the first submit; the rules are plain functions you can reuse and compose.
createListView
Search, filters, sort and pagination over any reactive source. The page goes back to 1 whenever the result set changes — derived, not effected.
| Team | Status | ||
|---|---|---|---|
Ada Okafor ada@acme.co | platform | active | 82% |
Bruno Sato bruno@acme.co | payments | away | 64% |
Chloé Martin chloe@acme.co | growth | active | 41% |
Dev Patel dev@acme.co | platform | active | 93% |
Elin Berg elin@acme.co | growth | offline | 27% |
Page 1 of 3
createAction
An async operation with loading, error and result, and a concurrency policy — declared in one object: run is the work, onSuccess and onError are what happens when it is over — you call toast there yourself, like anywhere else. Both receive the arguments run() was given. The AbortSignal run receives stops a restarted or cancelled call cleanly.
Click Save twice quickly: the first run is aborted and only one toast shows (concurrent: 'restart').
createLog
A reactive ring buffer for event feeds: push to the front, the oldest entries fall off.
Nothing yet.
Tones
Decide once how a status maps to a colour, then reuse it in every Badge, StatusPill and Progress. Typed: the result is exactly the set of tones you wrote.
thresholdTone(72, { warning: 70, danger: 85 })
warningFormat
Money, sizes, ages and dates. Pure, locale-aware, safe on the server; the Intl formatters are cached.
| Expression | Result |
|---|---|
money(1234.5) | $1,234.50 |
money(1234.5, { whole: true }) | $1,235 |
money(1234.5, { currency: 'EUR', locale: 'fr-FR' }) | 1 234,50 € |
compact(12_400) | 12.4K |
percent(0.421) | 42% |
bytes(1_240_000) | 1.2 MB |
plural(3, 'item') | 3 items |
age(5_400) | 1h |
relativeTime(twoHoursAgo) | 2 hours ago |
shortDate('2026-09-06') | Sep 6, 2026 |
shortDateTime('2026-09-06T10:40:00Z') | Sep 6, 10:40 AM |
Data
Totals, averages, groups and partitions with a key or a picker function — readable in a getter, no reduce.
Timing
Timers that are no-ops on the server, return their disposer and cancel cleanly.
Toast shorthands
One call per toast type; the object form stays available.