Premium · Accessible · Token-driven · Built on Base UI + Tailwind v4
🚀 Install · 🏗 Architecture · 🧩 Components · 🎨 Tokens · 🌍 i18n & motion · 📖 Storybook · 🚢 Release
| 🧩 140+ components | 📦 1 install | 🎨 WCAG-AA tokens | 🌗 Light + dark | 🌍 i18n + RTL | ⚛️ React 19 |
|---|---|---|---|---|---|
| shadcn + Base UI | @qeetrix/ui |
OKLCH · Style Dictionary | .dark class |
6 blocks · 5 brands | Tailwind v4 |
Status —
v1.0.0, live on npm. 🎉 The first stable release: 140+ components, 6 composable blocks, an i18n + motion layer, and status color-token triads — all in a single package. Tokens, brand, and blocks are folded into@qeetrix/ui; the API is stable (breaking changes now require a major bump). Already a production dependency of Qeet ID (admin · login · website), qeet-docs, qeet-notify, and qeet-logs.
| 📦 One install, everything in it | @qeetrix/ui ships components + design tokens + brand + blocks + i18n — no peer packages to wire up |
| ♿ Accessible by construction | Built on Base UI (WAI-ARIA APG behavior) + Vitest/axe on every interactive component; visible focus, reduced-motion, AA contrast |
| 🎨 Token-driven theming | W3C DTCG JSON → Style Dictionary → CSS + JSON; OKLCH colour, light/dark via the .dark class, 5 per-product brand overlays |
| 💎 Premium by default | Layered elevation, refined focus rings, tasteful hover-lift micro-interactions, self-hosted Qeet + Fira Code fonts |
| 🌍 Global-ready | Optional I18nProvider (locale + {var} interpolation) composes with DirectionProvider for RTL |
| 🌗 First-class dark mode | Every component themed through semantic tokens — no hard-coded greys |
| 🏢 Enterprise breadth | Data tables, command palette, rich-text editor, charts, sidebar shells, date/time pickers, QR codes, guided tours, and more |
| 🧱 Consistent foundation | Shared cva + cn() conventions, data-slot hooks, tree-shakeable named exports |
| 🔒 Quality-gated | Typecheck + Biome + Vitest/axe + WCAG contrast + Storybook build run in CI on every PR |
A Bun workspace monorepo that publishes a single consumable package. Tokens are the source of truth; everything downstream is generated or composed from them.
flowchart TB
subgraph src["packages/qeetrix-ui — @qeetrix/ui"]
direction LR
tokens["Design tokens<br/>W3C DTCG JSON · OKLCH<br/>tokens/"]
sd["Style Dictionary<br/>scripts/build-tokens.mjs<br/>→ semantic + raw --qx-* CSS + JSON"]
comps["140+ components<br/>shadcn + Base UI<br/>src/components/ui/"]
blocks["6 blocks + i18n + motion<br/>src/blocks/ · src/i18n/"]
brand["Brand<br/>QeetLogo + 10 icons<br/>src/brand/"]
tokens --> sd --> comps
brand --> comps --> blocks
end
consumers["Qeet ID · qeet-docs · qeet-notify · qeet-logs<br/>· future Qeet products"]
story["apps/qeetrix-story — Storybook 10 workshop"]
docs["apps/qeetrix-docs — ui.qeet.in (Next.js 16)"]
comps --> consumers
comps --> story
comps --> docs
Build pipeline (@qeetrix/ui): build-tokens (Style Dictionary) → tsc → tsc-alias → postbuild (inlines the token CSS, copies fonts + styles into dist/). The shared root package.json workspaces.catalog pins React / Tailwind / TS across the repo.
| Package | What it is | Published |
|---|---|---|
@qeetrix/ui |
The component library + tokens + brand + blocks + i18n — the one package consumers install | ✅ npm |
apps/qeetrix-story (@qeetrix/stories) |
Storybook 10 workshop — foundations gallery + a story per component (:6006) |
private |
apps/qeetrix-docs (qeetrix-docs) |
ui.qeet.in — the docs & developer platform, Next.js 16 + React 19 (:3006), dogfoods @qeetrix/ui |
private |
packages/qeetrix-mcp (@qeetrix/mcp) |
MCP server exposing the component + token manifest to AI coding agents | private |
Tooling is unified: linting + formatting run entirely on Biome (ESLint + Prettier removed); orchestration is plain
bun run --filter(no Turbo); TypeScript presets are self-contained per package (no shared config package).@qeetrix/tokensand@qeetrix/brandwere once separate packages — now folded into@qeetrix/uiand exposed as subpaths.
bun add @qeetrix/ui # components + tokens + brand + blocks + i18n, all in one
bun add react react-dom # peers (>= 19)In your Tailwind v4 global stylesheet:
@import "@qeetrix/ui/styles.css"; /* tokens + fonts + base layer */
@source "../node_modules/@qeetrix/ui/dist/**/*.js"; /* let Tailwind see component classes */Then wrap the app and compose:
import { ThemeProvider, Button, Card, CardContent } from "@qeetrix/ui";
import { QeetLogo } from "@qeetrix/ui/brand";
export function App() {
return (
<ThemeProvider defaultTheme="system">
<Card>
<CardContent className="flex items-center gap-3">
<QeetLogo size={28} />
<Button>Authenticate with Qeet</Button>
</CardContent>
</Card>
</ThemeProvider>
);
}Light/dark is driven by the .dark class (managed by ThemeProvider). Need raw values? @qeetrix/ui/tokens.css (the --qx-* ramp) and @qeetrix/ui/tokens.json.
| Surface | Contents |
|---|---|
@qeetrix/ui |
Components, providers, hooks, cn — the barrel |
@qeetrix/ui/styles.css |
Tokens + fonts + base layer (side-effect import) |
@qeetrix/ui/tokens.css · /tokens.json |
Raw --qx-* custom properties · resolved-per-theme JSON |
@qeetrix/ui/qeetrix.css |
Semantic token layer only |
@qeetrix/ui/brands/<brand>.css |
Per-product brand overlays (qeet-id · qeet-logs · qeet-notify · qeet-people · qeet-mail) |
@qeetrix/ui/brand |
QeetLogo + 10 custom Qeet icons |
@qeetrix/ui/blocks (+ /blocks/*) |
Composable multi-component patterns |
@qeetrix/ui/i18n |
I18nProvider · useTranslations · useI18n |
@qeetrix/ui/components/* · /lib/* · /hooks/* · /fonts/* |
Deep per-file imports |
140+ React components across the full enterprise surface — every one with a Storybook story; interactive ones with Vitest + axe tests. New in 1.0.0 ⭐
- Overlays & popovers — Dialog · AlertDialog · Sheet · Drawer · Popover · DropdownMenu · ContextMenu · Menubar · HoverCard · PreviewCard⭐ · Tooltip · ToggleTip⭐ · CommandPalette · NavigationMenu · Tour⭐ · Portal⭐ · FocusTrap⭐
- Inputs & controls — Button · ButtonGroup⭐ · IconButton⭐ · CloseButton⭐ · Input · PasswordInput⭐ · MaskInput⭐ · Textarea · Select · NativeSelect⭐ · Combobox · MultiSelect · Autocomplete · Checkbox · CheckboxCard⭐ · Radio · RadioCard⭐ · Switch · Toggle · Slider · AngleSlider · OTPInput · NumberField · CurrencyInput · Rating · Field / Form · Chip · TagInput · SegmentedControl · ColorPicker · ColorSwatch⭐ · Editable⭐ · Date / DateTime / TimeRange / Timezone pickers · Calendar
- Data & navigation — Table · DataTable · ActionBar⭐ · Tabs · Breadcrumb · Pagination · Sidebar · TreeView · Timeline · Accordion · Collapsible · Listbox · TableOfContents · Carousel · Charts (Area · Bar · Line · Donut · Radial · Sparkline) · OrgChart · MasterDetail · OverflowList · Resizable · ScrollArea
- Feedback & status — Card · Alert · Callout⭐ · Banner · Notification · NotificationCenter · Toast · Stat · Badge · StatusPill · PresenceIndicator · Skeleton · Progress · ProgressCircle⭐ · Meter · Spinner · EmptyState · DataState · Feed · Spoiler · Marquee · Timer⭐
- Content & utility — Typography / Prose · Blockquote · Highlight · Kbd · CodeBlock · DiffViewer · JSONTree · RichTextEditor · NumberFormatter · RollingNumber · Avatar · AspectRatio · Separator · VisuallyHidden⭐ · SkipNav⭐ · Link⭐ · CopyButton⭐ · CopyableSecret · QRCode⭐ · FileUpload · FileCard · LogoUploader · Icon
- Providers & hooks —
ThemeProvider·BrandProvider·DirectionProvider·I18nProvider·SidebarProvider·TooltipProvider· hooksuseIsMobile·usePrefersReducedMotion·useMotion·useCopyToClipboard·useFocusTrap·useTimer·useTour - Brand —
QeetLogo(theme-adaptive) + 10 custom Qeet icons, at@qeetrix/ui/brand - Blocks —
auth·dashboard-shell·onboarding-wizard·page-state·pricing-table·settings-layout, at@qeetrix/ui/blocks
The single source of truth lives in packages/qeetrix-ui/tokens/ as W3C DTCG JSON (primitives → light/dark semantic + shadcn bridge). Style Dictionary compiles them to:
@qeetrix/ui/styles.css— the full entry (semantic:root/.darkvars, baked in)@qeetrix/ui/tokens.css— the raw--qx-*ramp ·@qeetrix/ui/tokens.json— resolved per theme@qeetrix/ui/qeetrix.css— semantic layer only
Colour is authored in OKLCH; elevation uses a layered shadow ladder (rest · hover · popover · modal); the four status colours (success · warning · error · info) each ship a full foreground + background + border triad. Every semantic text/surface pair is held to WCAG-AA contrast by a build gate (bun run tokens:validate) — across all 5 brand overlays, in both themes.
The brand palette is Qeet orange (
#F26D0E≈orange.500), ratified asOD-DS-03. The--qx-color-brand-*ramp and the shadcn--primary/--ringbridge resolve to the OKLCH orange ramp (dark on-brand foreground for AA). Re-brand by re-pointing thecolor.brandaliases intokens/primitive/color.json.
import { ThemeProvider, DirectionProvider, I18nProvider, useMotion } from "@qeetrix/ui";
<ThemeProvider defaultTheme="system"> {/* .dark class → semantic tokens */}
<DirectionProvider dir="rtl"> {/* LTR / RTL, flows through components */}
<I18nProvider locale="hi" messages={hi}> {/* {var} interpolation, English fallback */}
<App />
</I18nProvider>
</DirectionProvider>
</ThemeProvider>- Brands —
<BrandProvider brand="qeet-id">setsdata-qx-brandon<html>, re-skinning primary/accent surfaces from the matching overlay. - Motion —
useMotion()+transition()/DURATION/EASINGcollapse to no-motion underprefers-reduced-motion.
Toolchain: Node ≥ 20 · Bun ≥ 1.3 (sole package manager). Biome for lint + format.
bun install
bun run build # @qeetrix/ui (tokens → tsc → postbuild) + Storybook + docs
bun run tokens:build # regenerate only the design tokens (Style Dictionary)
bun run tokens:validate # WCAG-AA contrast gate on the generated semantic pairs
bun run lint # biome check .
bun run format # biome format --write .
bun run typecheck
bun run --filter @qeetrix/ui test # Vitest + vitest-axe (675 tests)
bun run story:dev # Storybook component workshop → http://localhost:6006
bun run docs:dev # ui.qeet.in docs & platform → http://localhost:3006Adding a component? Drop it in packages/qeetrix-ui/src/components/ui/ (one flat file — cva + cn(), data-slot, Base UI for anything interactive), export it from src/index.ts, add a Storybook story + a Vitest/axe test, then record a changeset. See CONTRIBUTING.md.
Versioning + npm publishing run on Changesets:
bun run changeset # record a change (pick packages + bump)
bun run version:patch # or version:minor / version:major — apply a bump + changelog
bun run publish-packages # changeset publish (publishes changed public packages to npm)
bun run release # build all, then publish — the one-shot releaseCI runs Biome + typecheck + build + Vitest/axe + token contrast + Storybook on every PR (ci.yml), visual regression on stories (vrt.yml), and publishing to the @qeetrix npm org (release.yml, needs NPM_TOKEN). Scoped packages publish with publishConfig.access: "public".
| Topic | Where |
|---|---|
| 📦 Package on npm | @qeetrix/ui |
| 🧱 Component workshop | bun run story:dev → http://localhost:6006 |
| 🌐 Docs & platform | bun run docs:dev → http://localhost:3006 (ui.qeet.in) |
| 🤖 For AI assistants | CLAUDE.md — commands, architecture, gotchas |
| 🔧 Contributing | CONTRIBUTING.md |
| 📝 Changelog | packages/qeetrix-ui/CHANGELOG.md |
Part of the Qeet Group workspace alongside Qeet ID. Licensed UNLICENSED (private to Qeet Group) pending the public-release decision.