Skip to content

Kit catalog

24 components, grouped by how they hold state. The gallery (/ui-kit in the demo umbrella) shows every one live, and the browser e2e drives them all.

Pure slots — presentation only

No state; the parent projects content.

Component Notes
<Card> title / actions slots + default body
<Field> label / help / error around a control — also the substrate declui generates onto
<PageHeader> title + actions slot
<Stat> a KPI tile
<EmptyState> icon + message + action
<Avatar> initials or image; sizes via forwarded class
<Breadcrumb> links with CSS separators
<Tooltip> CSS hover tooltip

Attribute forwarding applies to every component: class on the host merges into the child's root; style/id/title/role/tabindex/aria-*/data-* are forwarded. A mistyped prop (anything else) fails closed.

Controlled — the parent owns the flag

Externally-triggered overlays: the opener lives elsewhere on the page, so the parent holds the Local and the wiring (:open prop + @close emit).

Component Contract
<Dialog> :open + @close; footer content via slots
<Drawer> side panel; same contract
<Toast> transient notice; pairs well with :autohide
<button @click="confirm_open = True" class="ui-btn ui-btn--primary">Delete…</button>
<Dialog :open="confirm_open" @close="close_confirm">
  <template slot="title">Delete 3 issues?</template>
  <button class="ui-btn ui-btn--danger" @click="do_delete()">Delete</button>
</Dialog>

Uncontrolled — the component owns its state

Self-triggered widgets: drop them in with zero parent wiring; each placement is monomorphized into independent state.

Component Notes
<Collapsible> an accordion row; N placements, N independent open flags
<Popover> trigger + panel, outside-click close
<Switch> on/off toggle
<TagInput> add/remove chips over a Local[list] (the client :each reconciler)
<Sortable> pointer drag-reorder via :sortable

Widget primitives — the optional runtime family

Complex widgets whose presentation state (open option, sort column, page) nothing else reads. They ship as a binder marker plus a runtime in widgets.js; your data and selection stay in Locals the app reads. Each is a deliberate, labelled runtime stand-in.

Component Binder State the app owns
<Tabs> :tabs — (bar generated from data-tab panels)
<DataTable> :table="rows" a Local[list]; header-click sorting
<DataGrid> :datagrid="rows" + :datagridsel="sel" rows Local[list] + selection Local[set] (survives sort/filter/page; tri-state select-all; aria-sort headers)
<Combobox> :combobox Local[str] — searchable single-select, full keyboard + ARIA listbox
<ComboboxMulti> :combobox (multi) Local[set] — chips, Backspace removes last
<Menu> :menu — (roving focus, Escape-to-trigger; each item keeps its compiled @click)
<CommandPalette> :palette — (Ctrl/⌘-K overlay, fuzzy filter, activates the item's compiled @click)

Native-wrapped

Component Notes
<Select> a real <select class="ui-select"> with :bind forwarding — keyboard and screen-reader behavior for free, zero runtime. The accessible default for a fixed option set; <Combobox> is the searchable upgrade.

Class-contract variants (no component needed)

Buttons (ui-btn, --primary/--danger/--ghost, sizes, loading), inputs (ui-input, invalid state), ui-badge--*, ui-alert--*, tables + pagination, ui-progress, ui-skeleton, ui-kbd. Write the class; there is nothing to instantiate.