Version: Current
Historical release snapshot. These docs are frozen. Read current docs.
@tcpsystems/ui: the shared UI library
Every web surface in the estate (console, studio, the ops harness console and
this site’s islands) builds on @tcpsystems/ui
(tcpsystems/ui, pinned in package.json at 78eedc4 as of 2026-11-03). It is
16 typed Svelte 5 components wrapping Bits UI v2 primitives in the suite
tokens, plus cn(), variants.ts and the style layers.
Live gallery
Section titled “Live gallery”Everything below is the real library rendering inside this page:
| Bits UI v2 primitive | Note | |
|---|---|---|
| Button / IconButton | Button.Root | variants via tailwind-variants, token-only |
| Dialog | Dialog.* | focus trap, Escape, overlay dismiss |
| Select | Select.* | single-value, portalled content |
| Switch | Switch.* | bindable checked |
| Tabs | Tabs.* | panel snippet per tab |
| Tooltip | Tooltip.* | UiProvider mounts the context |
| DropdownMenu | DropdownMenu.* | menu items with href or onSelect |
| Table / DataTable | native <table> | sortable headers, selection, aria-sort |
| Input | native <input> | real <label>, no hand-rolled ARIA |
| Badge / Skeleton | none | tone variants / aria-hidden div |
| Toast | svelte-sonner | toast() re-exported from the barrel |
| Card | none | .panel primitive + head/body/footer |
Components
Section titled “Components”UiProvider (Tooltip context), Button, IconButton, Input, Select,
Dialog, DropdownMenu, Tabs, Table (sortable and selectable, a native
<table> with aria-sort), DataTable, Badge, Switch, Tooltip,
Toast (svelte-sonner, toast re-exported), Card, Skeleton.
Bits UI v2 ships no input, table or skeleton primitive. Input is a native
<input> with a real <label>, Table is a native <table>, and Skeleton is
an aria-hidden div. Behaviour and ARIA from Bits UI are forwarded, never
stripped. Variant classes resolve only to semantic tokens, which a test pins: no
raw palette values.
Using it in a tcpsystems app
Section titled “Using it in a tcpsystems app”// package.json: pinned git dependency, source distribution via the svelte export condition"dependencies": { "@tcpsystems/ui": "github:tcpsystems/ui#<commit-sha>"}<script> import { UiProvider, Button, Badge } from '@tcpsystems/ui';</script>
<UiProvider> <Button variant="primary">Save</Button> <Badge tone="ok" dot>live</Badge></UiProvider>/* app entry CSS: after tailwindcss, with the library sources scanned */@import 'tailwindcss';@source '../node_modules/@tcpsystems/ui/src';@import '@tcpsystems/ui/styles/base.css';Three style layers ship separately, so a non-app surface such as this docs site can take tokens and primitives without the element reset:
@tcpsystems/ui/styles/base.css: tokens, primitives and base reset (apps: console, studio, ops console).@tcpsystems/ui/styles/tokens.css:@themewiring and thelight-dark()palette only.@tcpsystems/ui/styles/components.css: the.panel,.field,.inputand.data-tableprimitives only.
The @source line matters. Tailwind v4 auto-detection skips node_modules, so
without it the library’s utility classes silently do not compile.
- Semantic tokens only. Never raw palette values. A test enforces this.
- Keyboard-operable controls, focus-visible rings and forwarded ARIA are the floor, not a feature.
- Theme forcing is class-based.
.lightor.darkon<html>pinscolor-scheme; with neither class, the OS decides. - Add a component in
tcpsystems/uiwhen two products need it; product markup stays in the product repo. Library tests:pnpm testintcpsystems/ui.