@superboai/ui
v2.1.1
Published
Superbo UI Design System — a calm, precise, keyboard-first React component library for internal enterprise tooling.
Maintainers
Readme
@superboai/ui
The Superbo UI Design System as a React component library. Calm, precise, keyboard-first — built for dense enterprise admin consoles (first consumer: CHUB, the Ragulous RAG admin).
Think Linear / Retool / Notion, not marketing site. Density and legibility over decoration.
Install
npm i @superboai/uiPeer dependencies:
reactandreact-dom(^18.2.0 || ^19.0.0)tailwindcss^4.0.0— your app must run Tailwind v4
If you don't have Tailwind v4 in your app yet, install it first:
npm i -D tailwindcss @tailwindcss/vite # Vite
# or
npm i -D tailwindcss @tailwindcss/postcss # Next / PostCSSFollow the Tailwind v4 install guide for your framework.
Setup
1. Import the preset from your app's Tailwind entry CSS
/* app.css (or globals.css) — whatever your Tailwind entry is */
@import 'tailwindcss';
@import '@superboai/ui/preset';The preset ships our design tokens, @theme mappings, the dark custom
variant, the Karla / JetBrains Mono @imports, and a @source directive
that tells Tailwind to scan the library's built JS so every class the
components use lands in your output CSS.
2. Use components
import { Button } from '@superboai/ui';
export default function App() {
return <Button variant="primary">Save changes</Button>;
}That's it. Any semantic utility the components use (bg-bg-surface,
text-fg-muted, rounded-10, shadow-elev-2, bg-accent, etc.) is now
available in your own code too — with full Tailwind support for variants
(hover:, focus:, md:, dark:, …) and arbitrary values (p-[13px]).
Advanced: adding an explicit @source
Tailwind v4's official library-distribution guidance
shows consumers registering a library's source path themselves. You can
do this alongside our preset — @source declarations accumulate, so this
gives you extra control (e.g. scanning your own re-exports of our
components):
@import 'tailwindcss';
@import '@superboai/ui/preset';
@source "../node_modules/@superboai/ui";You generally won't need this — the preset already embeds a @source
that scans the library's built JS. Add an explicit one only if you need
your build to be robust to custom file layouts in your own project.
When do I need a provider?
Most apps need nothing. Components style themselves from the CSS you imported. Providers are only for specific runtime features:
| Feature | Provider needed |
| ---------------------------------------- | ------------------------------------------ |
| Runtime theme switching (light/dark) | <ThemeProvider> or <SuperboProvider> |
| Palette switching (indigo/cobalt) | <PaletteProvider> or <SuperboProvider> |
| <Tooltip> | <TooltipProvider> or <SuperboProvider> |
| toast() calls | <Toaster /> mounted once |
| None of the above | Nothing — just the CSS import |
Without ThemeProvider, components still respect the user's OS dark-mode
preference via prefers-color-scheme.
Mount only what you need
import { ThemeProvider, TooltipProvider, Toaster } from '@superboai/ui';
<ThemeProvider defaultTheme="system">
<TooltipProvider delayDuration={200}>
{children}
<Toaster />
</TooltipProvider>
</ThemeProvider>;Or use the convenience wrapper
import { SuperboProvider } from '@superboai/ui';
<SuperboProvider>{children}</SuperboProvider>;SuperboProvider mounts Theme + Palette + Tooltip + Toaster. Every piece
is opt-out: disableTheme, disablePalette, disableTooltip, disableToaster.
Theming
import { useTheme } from '@superboai/ui';
function ThemeSwitcher() {
const { theme, resolvedTheme, setTheme } = useTheme();
return (
<select value={theme} onChange={(e) => setTheme(e.target.value as 'light' | 'dark' | 'system')}>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">System ({resolvedTheme})</option>
</select>
);
}Requires <ThemeProvider> (or <SuperboProvider>) in the tree.
Preventing FOUC in SSR apps
Inline this script in <head> to apply the stored theme before first paint:
import { getSuperboThemeScript } from '@superboai/ui';
<head>
<script dangerouslySetInnerHTML={{ __html: getSuperboThemeScript() }} />
</head>;Design tokens
Every component is styled against semantic CSS custom properties that
flip with [data-theme="dark"] on <html>. They're exposed to Tailwind
via @theme so you can reach them as utility classes in your own markup —
no config needed.
Source: src/tokens/tokens.css and src/tokens/theme.css.
How to read the tables
- Semantic token — the CSS custom property name. Flips with theme.
- Tailwind utility — the ready-made class you'd normally reach for.
Works for every color-aware property (
bg-,text-,border-,ring-,outline-,divide-, etc.) — the table lists thebg-form; swap the prefix as needed. - Light / Dark — the resolved value in each theme.
Always prefer the semantic token. Raw palette steps (--indigo-500,
--neutral-700) are implementation detail and may be rewired by palette
swaps (data-palette="cobalt").
Surfaces / backgrounds
| Semantic token | Tailwind utility | Light | Dark |
| --------------- | ---------------- | -------------------- | -------------- |
| --bg-canvas | bg-bg-canvas | #fcfcfd neutral-50 | #0b0c0f |
| --bg-surface | bg-bg-surface | #ffffff | #14161b |
| --bg-sunken | bg-bg-sunken | neutral-100 | #0b0c0f |
| --bg-muted | bg-bg-muted | neutral-100 | #1c1f26 |
| --bg-hover | bg-bg-hover | 4% black | 4% white |
| --bg-active | bg-bg-active | 6% black | 6% white |
| --bg-selected | bg-bg-selected | indigo-50 | 12% indigo-400 |
| --bg-overlay | bg-bg-overlay | 40% black | 60% black |
Usage rule of thumb
bg-canvas— app background (the thing behind everything)bg-surface— cards, panels, modalsbg-sunken— inset areas (sidebars, code blocks)bg-muted— subtle fill (skeleton, chip background)bg-hover/bg-active— interaction statesbg-selected— persistent selection (row, nav item)bg-overlay— modal scrims
Foreground / text
| Semantic token | Tailwind utility | Light | Dark |
| --------------- | ------------------ | ----------- | ---------- |
| --fg-default | text-fg-default | neutral-900 | #f4f4f6 |
| --fg-muted | text-fg-muted | neutral-700 | #bfc1c8 |
| --fg-subtle | text-fg-subtle | neutral-500 | #8a8c94 |
| --fg-disabled | text-fg-disabled | neutral-400 | #4d5058 |
| --fg-onAccent | text-fg-onAccent | #ffffff | #0b0c0f |
| --fg-accent | text-fg-accent | indigo-600 | indigo-400 |
Usage rule of thumb
fg-default— body copy, headingsfg-muted— secondary copy, labelsfg-subtle— captions, meta, placeholdersfg-disabled— non-interactive text on disabled controlsfg-onAccent— text on top of accent-filled surfaces (buttons)fg-accent— links, active nav items, text-style accents
Borders
| Semantic token | Tailwind utility | Light | Dark |
| ------------------ | ----------------------- | ----------- | ---------- |
| --border-subtle | border-border-subtle | neutral-200 | #23262e |
| --border-default | border-border-default | neutral-300 | #2e323b |
| --border-strong | border-border-strong | neutral-400 | #3e424c |
| --border-focus | border-border-focus | indigo-500 | indigo-400 |
Usage rule of thumb
border-subtle— card edges, default dividersborder-default— input borders, table gridborder-strong— emphasized / hovered bordersborder-focus— focus rings (use onring-*andoutline-*utilities)
Accent (palette-swappable)
The accent family follows the active palette ([data-palette="cobalt"] on
<html> rewires these). Semantic statuses (success/info/warn/danger) stay
constant across palettes.
| Semantic token | Tailwind utility | Indigo (light) | Indigo (dark) |
| ----------------- | ---------------------- | -------------- | -------------- |
| --accent | bg-accent | indigo-500 | indigo-400 |
| --accent-hover | bg-accent-hover | indigo-600 | #a5b0fa |
| --accent-press | bg-accent-press | indigo-700 | #c2cafc |
| --accent-subtle | bg-accent-subtle | indigo-50 | 14% indigo-400 |
| --accent-border | border-accent-border | indigo-200 | 35% indigo-400 |
Status — success / info / warn / danger
Each status has four slots — background, foreground, icon, border.
| Token family | Light bg / fg / icon / border | Dark bg / fg / icon / border |
| ------------ | --------------------------------------------- | ------------------------------------------------- |
| success-* | #dcfce7 / #15803d / #16a34a / #16a34a | 15% #16a34a / #4ade80 / #22c55e / #22c55e |
| info-* | #dbeafe / #1d4ed8 / #2563eb / #2563eb | 18% #2563eb / #93c5fd / #60a5fa / #60a5fa |
| warn-* | #fef3c7 / #b45309 / #d97706 / #d97706 | 18% #d97706 / #fcd34d / #f59e0b / #f59e0b |
| danger-* | #fee2e2 / #b91c1c / #dc2626 / #dc2626 | 18% #dc2626 / #fca5a5 / #f87171 / #f87171 |
Tailwind utilities: bg-success-bg, text-success-fg, text-success-icon,
border-success-border (and info-, warn-, danger- variants).
Typography
Font families
| Token | Tailwind utility | Stack |
| ------------- | ---------------- | -------------------------------- |
| --font-sans | font-sans | Karla, system stack |
| --font-mono | font-mono | JetBrains Mono, system monospace |
The preset @imports Karla and JetBrains Mono from Google Fonts. If you
self-host fonts instead, override the variables in your own CSS:
:root {
--font-sans: 'Inter', system-ui, sans-serif;
}Font sizes
Size utilities are keyed on px values. Line-heights are baked in.
| Tailwind utility | Size | Line-height |
| ---------------- | ----- | ----------- |
| text-10 | 10 px | 1.5 (body) |
| text-11 | 11 px | 1.5 |
| text-12 | 12 px | 1.5 |
| text-13 | 13 px | 1.5 |
| text-14 | 14 px | 1.5 |
| text-15 | 15 px | 1.4 (snug) |
| text-16 | 16 px | 1.4 |
| text-18 | 18 px | 1.4 |
| text-20 | 20 px | 1.2 (tight) |
| text-24 | 24 px | 1.2 |
| text-32 | 32 px | 1.2 |
Standard Tailwind text-xs / text-sm / text-base / text-lg etc.
are also available. Use whichever scale reads better for your team.
Font weights
| Tailwind utility | Weight |
| ---------------- | ------ |
| font-regular | 400 |
| font-medium | 500 |
| font-semibold | 600 |
Radii
| Semantic token | Tailwind utility | Value |
| --------------- | ---------------- | ------ |
| --radius-6 | rounded-6 | 6 px |
| --radius-10 | rounded-10 | 10 px |
| --radius-14 | rounded-14 | 14 px |
| --radius-pill | rounded-pill | 999 px |
Tailwind's default rounded-sm / rounded-md / rounded-lg / rounded-xl
/ rounded-full are also available.
Elevation (shadows)
| Semantic token | Tailwind utility | Light | Dark |
| -------------- | ---------------- | -------------------------------------- | ------------------------------- |
| --elev-1 | shadow-elev-1 | 1 px border only | 1 px border only |
| --elev-2 | shadow-elev-2 | soft 12 px drop + border | 12 px drop (40% black) + border |
| --elev-3 | shadow-elev-3 | 48 px drop + border (modals, popovers) | 48 px drop (60% black) + border |
Motion
| Semantic token | Value |
| -------------------------------------- | ------------------------------- |
| --dur-fast | 120 ms |
| --dur-base | 180 ms |
| --dur-slow | 240 ms |
| --ease-out | cubic-bezier(0.16, 1, 0.3, 1) |
| --default-transition-duration | 120 ms (Tailwind default) |
| --default-transition-timing-function | --ease-out |
Every transition-* utility defaults to 120 ms + our ease curve — no
extra class needed for standard interactions.
Spacing
The spacing scale is standard Tailwind (0, 0.5, 1, 1.5, …, 96) at
the default 0.25rem base. Every utility (p-, m-, gap-, space-,
inset-, w-, h-, …) is available.
Our design scale is 4-based, which maps naturally:
| Tokens used in the design brief | Tailwind |
| ------------------------------- | ------------------- |
| --space-4 (4 px) | p-1 / m-1 / … |
| --space-8 (8 px) | p-2 / m-2 / … |
| --space-12 (12 px) | p-3 / m-3 / … |
| --space-16 (16 px) | p-4 / m-4 / … |
| --space-20 (20 px) | p-5 / m-5 / … |
| --space-24 (24 px) | p-6 / m-6 / … |
| --space-32 (32 px) | p-8 / m-8 / … |
| --space-40 (40 px) | p-10 / m-10 / … |
| --space-56 (56 px) | p-14 / m-14 / … |
| --space-80 (80 px) | p-20 / m-20 / … |
Row heights (for Tables, list items):
| Token | Value |
| ------------------- | ----- |
| --row-compact | 32 px |
| --row-comfortable | 40 px |
| --row-spacious | 48 px |
Using tokens outside Tailwind
Every semantic token is a real CSS variable, so they work anywhere CSS
works — inline styles, styled-components, plain .css:
.my-custom-surface {
background: var(--bg-surface);
color: var(--fg-default);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-10);
box-shadow: var(--elev-2);
transition: background var(--dur-fast) var(--ease-out);
}
.my-custom-surface:hover {
background: var(--bg-hover);
}No extra import needed — the variables are on :root once
@superboai/ui/preset is in your Tailwind entry CSS.
Next.js (App Router) notes
All interactive components are marked 'use client'. You can import them
from any Server Component:
// app/page.tsx — Server Component
import { Button } from '@superboai/ui';
export default function Page() {
return <Button variant="primary">Go</Button>;
}Mount the provider (if you need one) inside a client boundary:
// app/providers.tsx
'use client';
import { SuperboProvider } from '@superboai/ui';
export function Providers({ children }: { children: React.ReactNode }) {
return <SuperboProvider>{children}</SuperboProvider>;
}
// app/layout.tsx
import { Providers } from './providers';
import { getSuperboThemeScript } from '@superboai/ui';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<script dangerouslySetInnerHTML={{ __html: getSuperboThemeScript() }} />
</head>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}@import "@superboai/ui/preset" goes in your Tailwind entry CSS
(e.g. app/globals.css).
Components
Form: Button, Input, InputGroup, HelpText, Label, Textarea,
Select (+ parts), Multiselect, Checkbox, Switch, RadioGroup,
Slider, Toggle
Display: Badge, Chip, Card (+ parts), Table (+ parts),
Pagination, Alert (+ parts), Progress, Spinner, Skeleton,
Avatar (+ parts), Kbd, Separator, Breadcrumb, Accordion
Overlays: Dialog (+ parts), DropdownMenu (+ parts), Menubar,
Popover (+ parts), Tooltip (+ parts), ScrollArea, Tabs (+ parts),
Command / CommandDialog (+ parts), Toaster + toast
Providers: SuperboProvider, ThemeProvider, PaletteProvider,
TooltipProvider, useTheme, usePalette
Utilities: cn, getSuperboThemeScript
Package exports
| Specifier | What it is |
| -------------------------- | ------------------------------- |
| @superboai/ui | Component library (JS + types) |
| @superboai/ui/preset | Tailwind v4 preset CSS |
| @superboai/ui/tokens.css | Raw CSS variables (tokens only) |
Voice & content
Superbo UI is a utility system; copy carries the same weight as the visuals. Sentence case. No emoji. No exclamation marks except genuine warnings. Technical, direct, no filler.
| Avoid | Use | | ------------------------- | -------------------------------------------------- | | "Oops, nothing here yet!" | "No records found." | | "We couldn't connect." | "Connection failed. Check the endpoint and retry." | | "Let's get started!" | "Connect a data source to begin." |
Development
npm install
npm run dev # playground at http://localhost:5173
npm run typecheck
npm run lint
npm run build # emits dist/ (JS + types + preset.css + tokens)
npm pack # verifies the published tarball shapeThe build pipeline:
build:js— Vite library build, one file per source module so consumers' bundlers tree-shake at file granularity.build:preset— Copies the preset CSS and tokens todist/so consumers can@import '@superboai/ui/preset'.
The playground in playground/ is a live demo harness that aliases
@superboai/ui to the local source. Changes in src/ hot-reload.
License
UNLICENSED — internal Superbo use only until a public release is decided.
