@arki/ui

For @arki/[email protected] · source README.md

React component library for ARKI apps: Base UI primitives styled with Tailwind v4 semantic tokens. Forms, overlays, navigation, data display and charts. One import per component.

Install

bun add @arki/ui @arki/design-systems @arki/theme react react-dom

react and react-dom 19 are peer dependencies. @arki/design-systems supplies the tokens the components read, and @arki/theme sets light and dark mode.

Quick start

Pick one design system and let Tailwind scan the component sources.

/* src/styles/global.css */
@import 'tailwindcss';
@import '@arki/design-systems/atelier/fonts.css';
@import '@arki/design-systems/atelier/tokens.css';
@import '@arki/design-systems/atelier/theme-bridge.css';
 
/* Adjust the path to where @arki/ui is installed. */
@source '../node_modules/@arki/ui/src';

Then import each component from its own subpath.

import { Button } from '@arki/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@arki/ui/card';
import { cn } from '@arki/ui/cn';
 
export function Example() {
  return (
    <Card className={cn('max-w-md')}>
      <CardHeader>
        <CardTitle>Tidal Mug</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>Add to cart</Button>
      </CardContent>
    </Card>
  );
}

When not to use this

  • Your app does not use Tailwind v4. The components are styled with Tailwind classes and have no stylesheet of their own.
  • You need a headless library to style yourself. Use @base-ui/react directly. This package is the styled layer on top of it.
  • You mix design systems in one app. These components read one set of tokens (see @arki/design-systems).
  • You build for React Native. Use @arki/native-ui.

Runtime support

Source-distributed: ships TypeScript/TSX, needs a bundler (Vite with the TanStack Start stack).

Public imports

There is no root import. Every component is its own subpath: @arki/ui/button, @arki/ui/dialog, @arki/ui/select, @arki/ui/table, @arki/ui/chart. llms.txt lists all of them with their names.

GroupSubpaths
Actionsbutton, toggle, toggle-group, toolbar, control-group
Formsform, input, input-base, input-otp, textarea, textarea-with-autosize, select, checkbox, radio-group, switch, slider, label, date-picker, color-picker, math-input, complex-input
Overlaysdialog, alert-dialog, drawer, sheet, popover, hover-card, tooltip, command, sonner (toasts)
Menus and navigationdropdown-menu, context-menu, menubar, navigation-menu, breadcrumb, pagination, tabs, sidebar
Layout and surfacescard, glass-card, panel, surface, separator, scroll-area, resizable, tool-panels, aspect-ratio, accordion, collapsible
Data displaytable, chart, badge, avatar, alert, callout, progress, skeleton, spinners, timeline, carousel, calendar, katex
Helperscn, design-system, slot, as-child, scroll-to-top

Failure behaviour

Components do not return failure values. Mistakes in how you compose them show up in three ways.

  • Some compound parts need their parent. These hooks throw a plain Error when the parent is missing: useFormField (inside FormField), useSidebar (inside SidebarProvider), and the hooks for Chart, Carousel, ControlGroup and Timeline. Fix the tree; do not catch the error.
  • A missing token gives a wrong colour, not an error. If a page looks unstyled, check the @source line and the token imports first.
  • Toaster reads the theme from @arki/theme. Without a ThemeProvider it uses system.

Limits

  • Tailwind only sees classes it can scan. If @source does not point at the installed @arki/ui/src, components render with no styling and no error.
  • Pick one design system per app. Boundary: loading atelier tokens and workbench tokens in one stylesheet makes the later file win for every shared name, so components mix two palettes.
  • katex does not load KaTeX's stylesheet. Import katex/dist/katex.min.css yourself, or maths renders unstyled.
  • Imports must name a subpath. import { Button } from '@arki/ui' fails: the package has no root entry.
  • Some components rely on browser APIs (matchMedia, ResizeObserver). Render them on the client; in tests use a DOM environment.

Design-system rules

  1. Style with semantic classes: bg-background, bg-card, text-muted-foreground, border-border.
  2. One design system per app: atelier, workbench or arena. Never mix them.
  3. App-specific colours get new token names. Do not redefine a shared name.
  4. If a component needs a token the contract does not have, propose the smallest extension and get confirmation before you change @arki/design-systems.

Benchmarks

Bundle size of the same components from @arki/ui and from popular React component libraries. Mantine, MUI and Radix Themes are the common full-featured choices.

Measured on Node 22.13.1 (Darwin 27.0.0 arm64, Apple M2 Max (12 cores)) · @arki/bench 0.0.1 (mitata 1.0.34) · publish, seed 1592639052 · commit 34146416b3 (uncommitted changes) · 2026-10-13.

Versions: @arki/bench 0.0.1 · @arki/ui 0.1.4 · @mantine/core 7.17.4 · @mui/material 9.5.0 · @radix-ui/themes 3.3.0 · mitata 1.0.34.

Button, JavaScript only

Rows marked different contract do other work: they are measured and shown, never ranked.

LibraryVersionJS+CSS gzipbrotlirawBudget (gzip)vs @arki/ui
@arki/ui0.1.412.9 kB11.5 kB39.4 kB14.5 kBbaseline
@mantine/core7.17.412.1 kB10.7 kB40.5 kB—different contract: ships a separate stylesheet that this row does not count
@mui/material9.5.037.7 kB33.6 kB110 kB—different contract: styles are injected at runtime by Emotion (CSS-in-JS), not a stylesheet
@radix-ui/themes3.3.05.32 kB4.79 kB17 kB—different contract: ships a separate stylesheet that this row does not count

Dialog, JavaScript only

Rows marked different contract do other work: they are measured and shown, never ranked.

LibraryVersionJS+CSS gzipbrotlirawBudget (gzip)vs @arki/ui
@arki/ui0.1.432 kB28.6 kB97.6 kB35.5 kBbaseline
@mantine/core7.17.420.5 kB18.2 kB66.4 kB—different contract: ships a separate stylesheet that this row does not count
@mui/material9.5.040 kB35.4 kB117 kB—different contract: styles are injected at runtime by Emotion (CSS-in-JS), not a stylesheet
@radix-ui/themes3.3.019.3 kB17.3 kB58.3 kB—different contract: ships a separate stylesheet that this row does not count

Form set (Button, Input, Select, Checkbox), JavaScript only

Rows marked different contract do other work: they are measured and shown, never ranked.

LibraryVersionJS+CSS gzipbrotlirawBudget (gzip)vs @arki/ui
@arki/ui0.1.457.5 kB50.4 kB169 kB63.5 kBbaseline
@mantine/core7.17.443 kB38 kB140 kB—different contract: ships a separate stylesheet that this row does not count
@mui/material9.5.068.5 kB59.5 kB213 kB—different contract: styles are injected at runtime by Emotion (CSS-in-JS), not a stylesheet
@radix-ui/themes3.3.043.5 kB38.4 kB133 kB—different contract: ships a separate stylesheet that this row does not count

Button, complete styled

LibraryVersionJS+CSS gzipbrotlirawBudget (gzip)vs @arki/ui + Tailwind CSS
@arki/ui + Tailwind CSS0.1.417 kB15 kB58.2 kB18.5 kBbaseline
@mantine/core + styles.css7.17.444.3 kB36.5 kB338 kB—2.6× larger [2.6–2.6]
@mui/material (Emotion)9.5.037.7 kB33.6 kB110 kB—2.2× larger [2.2–2.2]
@radix-ui/themes + styles.css3.3.086.1 kB54.4 kB731 kB—5.1× larger [5.1–5.1]

Dialog, complete styled

LibraryVersionJS+CSS gzipbrotlirawBudget (gzip)vs @arki/ui + Tailwind CSS
@arki/ui + Tailwind CSS0.1.437 kB32.9 kB121 kB41 kBbaseline
@mantine/core + styles.css7.17.452.7 kB44.1 kB363 kB—1.4× larger [1.4–1.4]
@mui/material (Emotion)9.5.040 kB35.4 kB117 kB—1.08× larger [1.08–1.08]
@radix-ui/themes + styles.css3.3.0100 kB66.9 kB773 kB—2.7× larger [2.7–2.7]

Form set (Button, Input, Select, Checkbox), complete styled

LibraryVersionJS+CSS gzipbrotlirawBudget (gzip)vs @arki/ui + Tailwind CSS
@arki/ui + Tailwind CSS0.1.463.2 kB55.4 kB197 kB69 kBbaseline
@mantine/core + styles.css7.17.475.2 kB63.8 kB437 kB—1.2× larger [1.2–1.2]
@mui/material (Emotion)9.5.068.5 kB59.5 kB213 kB—1.08× larger [1.08–1.08]
@radix-ui/themes + styles.css3.3.0124 kB88 kB848 kB—2.0× larger [2.0–2.0]

Notes

  • Styling is not equal, so there are two kinds of group. JavaScript only counts the components without styles; a rival that needs a stylesheet or styles itself at runtime is measured but never ranked (differs). complete styled adds the CSS a user must also ship, and ranks everything.
  • @arki/ui is Base UI primitives styled with Tailwind classes. Its CSS comes from your app Tailwind build. In the complete styled groups it is a Tailwind v4 build of the classes found in the measured component files (found by Tailwind’s own scanner), with preflight and the workbench tokens and theme bridge. Fonts are left out. A real app adds the classes of its own code on top.
  • Mantine and Radix Themes ship one stylesheet for the whole library (styles.css), not a per-component one, so their complete rows include the CSS of every component. MUI styles components at runtime with Emotion, so its JavaScript includes the styling engine and it has no stylesheet.
  • Mantine Modal and MUI/Radix Dialog are the nearest equivalents of the @arki/ui Dialog parts.

Reproduce: bunx arki-bench run --profile publish in the package directory.

  • @arki/design-systems: tokens, Tailwind bridge and fonts for atelier, workbench, arena.
  • @arki/theme: light, dark and system provider and the no-flash script.
  • @arki/icons: icon sets behind one React entry point.
  • @arki/react-hooks: the hooks the components use, reusable on their own.

Documentation

Support

Report bugs and questions at https://github.com/arki-labs/arki/issues.

License

MIT. See LICENSE.

All docs for @arki/[email protected]