# jarvis-react-ui > Sharp, dark, HUD-style React 19 component library (JARVIS look: JetBrains Mono, glow instead of shadows): primitives, inputs, dialogs, toasts, tables, charts, a window/slot-grid system, a CSS and a Three.js orb, and built-in UI sound effects. Version 0.5.0. Docs: https://joeyash.github.io/jarvis_ui_lib/ ## Usage rules - Install `jarvis-react-ui` with its peers `react` and `react-dom` (^19) and `lucide-react`. `three` is an optional peer, needed only for `ThreeOrb`. - Import the stylesheet once at the app root: `import 'jarvis-react-ui/style.css';`. Tailwind is not required in the consuming project. - Import components, hooks and types from the package root only: `import { Button, Panel } from 'jarvis-react-ui';`. Never deep-import from `jarvis-react-ui/dist/...`. - `ThreeOrb`, `createOrb` and `OrbEngine` come from `jarvis-react-ui/orb` (separate entry so `three` stays out of the main bundle). `CssOrb` is in the main entry. - Wrap the app once in `JarvisProvider` (UI sounds, toasts, `useJarvis()`). `useToast()` and `useJarvis()` throw outside of it; without a provider the other components work but stay silent. - Give the page the dark surface: `body { background: var(--bg); color: var(--text); }`. Style with the design tokens (`var(--accent)`, ...), not hard-coded colors. - Every component accepts `className`; components wrapping a native element accept its attributes and forward `ref`. - Layout: use `Stack` (rows/columns) and `Grid` (columns) with token gaps (`xs`–`xl`); sizes via the project's own CSS classes, or Tailwind only if the project has Tailwind. The demos below use Tailwind utilities (`flex gap-3`, `w-[280px]`) for layout; without Tailwind, replace them with `Stack`, `Grid` or own CSS. Do not rely on utility classes from `style.css`: it contains only an internal subset that changes between releases. - Windows built at runtime from JSON (e.g. by an assistant): `UiRenderer`, `useUiWindows` and `validateUiSpec` come from `jarvis-react-ui/generative`. A spec may only use the components and props of `UI_REGISTRY` (see the UiRenderer page); validate specs before opening them. The JSON Schema of a spec and Claude tool definitions ship as `jarvis-react-ui/ui-schema.json` and `jarvis-react-ui/ui-tools.json`. - Use only the props listed in the API tables; do not invent props or variants. Helper types used by props (e.g. `TabItem`, `TableColumn`) are documented under "Type" after each API table. # Overview ## What's inside - **Primitives**: buttons, inputs, switches, pills, metrics, progress bars, sparklines, panels and decorative HUD layers such as corner brackets, scanlines and light traces. - **Compositions**: navigation lists, tabs, tables, code blocks, callouts, a HUD shell, a status dock and the `WindowManager`. - **Window system**: draggable, resizable windows on a 9-slot snap grid, with the hooks to build your own. - **Orbs**: `CssOrb` with five states in the main entry, `ThreeOrb` in `jarvis-react-ui/orb`. - **Sound**: an audio engine and React hooks that give every interactive component hover and click sounds. Start with [Installation](https://joeyash.github.io/jarvis_ui_lib/getting-started/installation.md), then build your first screen in [Usage](https://joeyash.github.io/jarvis_ui_lib/getting-started/usage.md). # Installation Install the package and its peer dependencies, import the stylesheet once, and you are ready to render your first component. ## Install the package ```bash npm i jarvis-react-ui ``` The library has three peer dependencies. Install them if your project does not have them yet: ```bash npm i react react-dom lucide-react ``` | Package | Version | Why | | -------------------- | -------- | --------------------------------------------------------------------- | | `react`, `react-dom` | `^19` | The components use React 19 APIs. | | `lucide-react` | `^1` | Icons used inside components and accepted by `Icon` and `IconButton`. | | `three` | optional | Only for `ThreeOrb` from `jarvis-react-ui/orb`. | ## Import the stylesheet Import the compiled stylesheet once, at the root of your app: ```tsx // main.tsx import 'jarvis-react-ui/style.css'; ``` It contains the design tokens (CSS custom properties), the compiled utility layer the components use, keyframes and all component styles. It also loads JetBrains Mono from Google Fonts and includes Tailwind's preflight reset. You do **not** need Tailwind in your project. > The preflight reset normalizes margins, headings and form elements. Import the stylesheet before > your own styles so your rules win. ## Package entry points | Import | Contents | | --------------------------- | ---------------------------------------------------------- | | `jarvis-react-ui` | All components, hooks, the audio API, utilities and types. | | `jarvis-react-ui/orb` | `ThreeOrb`, `createOrb` and `OrbEngine` (needs `three`). | | `jarvis-react-ui/style.css` | The stylesheet. | | `jarvis-react-ui/sounds/*` | The bundled sound files. | The package is ESM only and ships TypeScript declarations. The Three.js orb lives in its own entry, so `three` never ends up in your bundle unless you import it. ## Upgrading After `npm install jarvis-react-ui@`, restart the Vite dev server with `npm run dev -- --force` (or delete `node_modules/.vite`). npm writes package files with fixed timestamps, so Vite's dependency cache may keep serving the old `style.css` or JavaScript otherwise. ## Next steps - Build a first screen in [Usage](https://joeyash.github.io/jarvis_ui_lib/getting-started/usage.md). - Turn on sounds in [Sound effects](https://joeyash.github.io/jarvis_ui_lib/getting-started/sound.md). - Change the colors in [Theming](https://joeyash.github.io/jarvis_ui_lib/customization/theming.md). # Usage Components are plain React components with typed props. Compose them like any other UI kit; the HUD look comes from the shared design tokens. ## Wrap your app Mount [JarvisProvider](https://joeyash.github.io/jarvis_ui_lib/components/jarvis-provider.md) once at the root. It sets up UI sounds, toasts and the `useJarvis()` controls: ```tsx // main.tsx import 'jarvis-react-ui/style.css'; import { createRoot } from 'react-dom/client'; import { JarvisProvider } from 'jarvis-react-ui'; import { App } from './App'; createRoot(document.getElementById('root') as HTMLElement).render( , ); ``` ## A first panel ```tsx import { Button, Metric, Panel, Pill, useToast } from 'jarvis-react-ui'; export function App() { const { toast } = useToast(); return ( online ); } ``` ## Dark background The components are designed for the dark JARVIS background. Give your page the background token so everything sits on the right surface: ```css body { background: var(--bg); color: var(--text); } ``` For the full HUD look, add the decorative layers `GridBackground`, `Scanlines` and `ViewportCorners`, or the complete `HUDShell` frame. ## Layout The components bring their own styles; the layout around them is yours. Size and place them with `className` and your own CSS (or Tailwind, if your project uses it): ```css .reactor-panel { width: 320px; height: 220px; } ``` For rows, columns and grids use [Stack](https://joeyash.github.io/jarvis_ui_lib/components/stack.md) and [Grid](https://joeyash.github.io/jarvis_ui_lib/components/grid.md): they space their children with the design tokens and need no Tailwind. ```tsx online ``` The demos on these pages lay themselves out with Tailwind utilities such as `flex gap-3`. Without Tailwind in your project, replace those with `Stack`, `Grid` or your own CSS: the utility classes inside `style.css` are an internal subset and not meant for your markup (see [Tailwind](https://joeyash.github.io/jarvis_ui_lib/customization/tailwind.md)). ## Props and refs - Every component accepts `className`, merged onto its root element. - Components that wrap a native element (`Button`, `IconButton`, `Input`, `Link`, `Switch`) accept that element's attributes (`onClick`, `disabled`, `aria-*`, ...) and forward their `ref`. - Controlled and uncontrolled modes follow React conventions: `value` / `defaultValue` with `onValueChange` (Tabs), `checked` / `defaultChecked` with `onCheckedChange` (Switch). Each component page ends with an **API** table generated from the TypeScript types, so it always matches the source. ## Client-side routing Links and navigation entries render real `` elements. To use them with a router, prevent the default navigation and call your router instead: ```tsx import { useNavigate } from 'react-router'; import { NavList } from 'jarvis-react-ui'; export function Sidebar() { const navigate = useNavigate(); return ( { event.preventDefault(); navigate(item.href); }} /> ); } ``` This documentation site is built exactly like that, using only `jarvis-react-ui` components. ## TypeScript All props, variants and helper types are exported next to their component: ```ts import type { ButtonProps, ButtonVariant, TableColumn } from 'jarvis-react-ui'; ``` # Sound effects Interactive components play short UI sounds (hover, click, drag, boot, ...) through a React context. Without a provider they stay silent, so audio is strictly opt-in. ## Enable sound [JarvisProvider](https://joeyash.github.io/jarvis_ui_lib/components/jarvis-provider.md) turns sound on for the whole app. Sound is on by default; `sfx={false}` starts muted, and `useJarvis()` returns `{ isMuted, toggleMute }` for a mute switch. The user's choice is stored in `localStorage`, so it survives reloads. Try the **SFX** switch in the header of this site. ```tsx import { JarvisProvider } from 'jarvis-react-ui'; ; ``` ### Manual setup Without `JarvisProvider`, mount the audio engine yourself and pass it to `SfxProvider`: ```tsx import type { ReactNode } from 'react'; import { SfxProvider, useAudioEngine } from 'jarvis-react-ui'; export function SoundRoot({ children }: { children: ReactNode }) { const { playOneShot, play, stop } = useAudioEngine('idle', true, false, { initialMuted: false, }); return ( {children} ); } ``` > Browsers only start audio after a user gesture. The first sounds play after the first click or key > press on the page. ## Serve the sound files The sound files ship inside the package under `public/sounds`. The engine loads them from a base URL that defaults to `/sounds/` on your site. **Option 1: copy them into your static folder** (no configuration): ```bash cp -r node_modules/jarvis-react-ui/public/sounds public/sounds ``` **Option 2: point `soundBaseUrl` at your own path or a CDN** (pin the version in the URL): ```tsx const { playOneShot, play, stop } = useAudioEngine('idle', true, false, { soundBaseUrl: 'https://cdn.jsdelivr.net/npm/jarvis-react-ui@0.1.0/public/sounds/', }); ``` The value may be relative or absolute; a trailing slash is added if missing. Query strings and hashes are rejected. The engine is a process-wide singleton, so the last applied URL wins. A CDN must send CORS headers (unpkg and jsDelivr do). Missing files are logged and skipped; nothing throws. ## Sounds in your own components | Hook | Use | | ----------------------- | ---------------------------------------------------------------------------------------------- | | `useClickSfx(onClick)` | Wraps a click handler: plays `click`, then calls yours. | | `useHoverSfx('button')` | Returns an `onMouseEnter` handler that plays a throttled hover sound (`'panel'` for surfaces). | | `useSfx()` | `{ playOneShot, play, stop }` for any other sound event. | ```tsx import { useClickSfx, useHoverSfx } from 'jarvis-react-ui'; export function ScanButton({ onScan }: { onScan: () => void }) { const onMouseEnter = useHoverSfx('button'); const onClick = useClickSfx(onScan); return ( ); } ``` Mark buttons with `data-sfx-hover="button"` so the hover sound of a surrounding panel does not play on top of the button's own. # JarvisProvider The root provider of a JARVIS app. It starts the audio engine for UI sounds, provides toasts and exposes app-level controls through `useJarvis()`. Wrap your app in it once. ```ts import { JarvisProvider } from 'jarvis-react-ui'; ``` ## Setup ```tsx import 'jarvis-react-ui/style.css'; import { createRoot } from 'react-dom/client'; import { JarvisProvider } from 'jarvis-react-ui'; import { App } from './App'; createRoot(document.getElementById('root') as HTMLElement).render( , ); ``` Everything below it can use [useToast](https://joeyash.github.io/jarvis_ui_lib/components/toast.md), `useJarvis()` and the sound hooks, and all interactive components play their sounds. ```tsx import { Button, Panel, useJarvis, useToast } from 'jarvis-react-ui'; export default function Everything() { const { isMuted } = useJarvis(); const { toast } = useToast(); return (
Sound {isMuted ? 'off' : 'on'} · toasts ready
); } ``` ## Sound Sound is **on by default**. Browsers only start audio after the first click or key press. - `sfx={false}` starts muted. Users can still switch sound on, e.g. with a toggle bound to `useJarvis()`. - `useJarvis()` returns `{ isMuted, toggleMute }`. The user's choice is stored in `localStorage` and wins over the `sfx` prop on the next visit. - `soundBaseUrl` points the engine at your copy of the sound files or a CDN, see [Sound effects](https://joeyash.github.io/jarvis_ui_lib/getting-started/sound.md). ```tsx import { Button, Pill, Switch, useJarvis } from 'jarvis-react-ui'; export default function MuteToggle() { const { isMuted, toggleMute } = useJarvis(); return ( <> {isMuted ? 'muted' : 'live'} ); } ``` ```tsx ``` ## Assistant state `orbState`, `connected` and `heartbeat` feed the audio engine's state sounds (ambient loop, scan while listening, offline alerts). Pass your assistant's current state to keep the soundscape in sync with the orb. ## Toasts `toastPlacement`, `toastMax` and `toastDuration` configure the built-in [ToastProvider](https://joeyash.github.io/jarvis_ui_lib/components/toast-provider.md). ## Without JarvisProvider The building blocks stay available on their own: `SfxProvider` with `useAudioEngine` for sound and `ToastProvider` for toasts. ## API | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` (required) | `ReactNode` | | Your app. | | `connected` | `boolean` | `true` | Connection state; `false` plays the disconnect/offline sounds. | | `heartbeat` | `boolean` | `false` | Plays a heartbeat loop while idle. | | `orbState` | `'idle' \| 'listening' \| 'thinking' \| 'speaking' \| 'follow_up' \| 'working'` | `'idle'` | Assistant state driving the ambient/state sounds of the audio engine. | | `sfx` | `boolean` | `true` | Whether UI sounds start enabled. `false` starts muted; `useJarvis().toggleMute()` can still switch them on. A preference the user set earlier (stored in `localStorage`) wins. | | `soundBaseUrl` | `string` | `'/sounds/'` | Where the sound files are served from, e.g. a CDN URL. | | `toastDuration` | `number` | `5000` | Default toast lifetime in ms. | | `toastMax` | `number` | `3` | Maximum number of toasts shown at once. | | `toastPlacement` | `'bottom-right' \| 'top-right' \| 'bottom-center' \| 'top-center'` | `'bottom-right'` | Corner or edge where toasts appear. | # Using with AI The docs are also published as plain Markdown for AI coding assistants, so they use the real props and imports instead of guessing. The same files ship in the npm package and always match the installed version. ## On the web The docs site follows the [llms.txt](https://llmstxt.org) convention: | File | Contents | | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [`/llms.txt`](https://joeyash.github.io/jarvis_ui_lib/llms.txt) | Usage rules and a link to every page, with a one-line summary. | | [`/llms-full.txt`](https://joeyash.github.io/jarvis_ui_lib/llms-full.txt) | Every page in one file, with the demo code and the API tables. | | `/.md` | One page as Markdown, e.g. `/components/button.md` for this site's Button page. | Point a chat assistant at `llms-full.txt`, or at the `.md` pages it needs. ## In the package The package contains the same content for the version you installed: | File | Contents | | ------------------------------------------------- | ----------------------------------------------------------------------------------------- | | `node_modules/jarvis-react-ui/dist/llms.txt` | Usage rules and the page index. | | `node_modules/jarvis-react-ui/dist/llms-full.txt` | All pages with demo code and API tables. | | `node_modules/jarvis-react-ui/dist/api.json` | Every public component: entry point, props (type, default, description) and demo sources. | They are also exported as `jarvis-react-ui/llms.txt`, `jarvis-react-ui/llms-full.txt` and `jarvis-react-ui/api.json`, so tools can resolve them with `require.resolve`. ## Tell your assistant Coding agents read project instructions such as `CLAUDE.md`, `AGENTS.md` or `.cursorrules`. Add a short note so they load the docs before writing UI code: ```md ## UI components This app uses `jarvis-react-ui`. Before building or changing UI, read `node_modules/jarvis-react-ui/dist/llms-full.txt` and use only the components, props and imports documented there. ``` `llms-full.txt` is large. Agents that search files can read `api.json` or grep `llms-full.txt` for the component they need instead of loading all of it. ## Let an assistant build windows The files above help assistants that **write code** with the library. To let a model **build UI at runtime**, for example a voice assistant that opens a video window or a volume control, use the generative entry: the model sends JSON specs through tools, and [UiRenderer](https://joeyash.github.io/jarvis_ui_lib/components/ui-renderer.md) renders them with library components. The package ships the JSON Schema (`jarvis-react-ui/ui-schema.json`) and ready-made tool definitions (`jarvis-react-ui/ui-tools.json`); see [Connecting an assistant](https://joeyash.github.io/jarvis_ui_lib/generative/assistant.md). # Theming Every color, glow, radius, spacing step and timing is a CSS custom property. Components read only those tokens, so overriding a few variables re-themes the whole library at runtime. ## Theme the whole app Override the variables on `:root`, after importing the stylesheet: ```css :root { --accent: #e8a84c; --accent-bright: #ffc76e; --accent-dim: #a1702d; --border-bright: #4f3d2a; /* glows: the component stylesheets read --glow*, the glow utilities read --shadow-glow* */ --glow: 0 0 8px #e8a84caa; --glow-strong: 0 0 20px #e8a84ccc, 0 0 40px #e8a84c44; --shadow-glow: 0 0 8px #e8a84caa; --shadow-glow-strong: 0 0 20px #e8a84ccc, 0 0 40px #e8a84c44; } ``` You can also change them from JavaScript, e.g. `document.documentElement.style.setProperty('--accent', color)`, to switch themes at runtime. ## Theme one area The utility colors are aliases declared on `:root` (`--color-accent: var(--accent)`), so they are resolved there. To re-theme only a sub-tree, set the alias next to the token: ```css .my-area { --accent: #e8a84c; --color-accent: #e8a84c; } ``` ## Playground Pick a preset. It is applied to the preview only, and the CSS below it is the complete scoped override, including the `--color-*` and `--shadow-glow*` aliases. ## What to override - **Accent**: `--accent`, `--accent-bright`, `--accent-dim` drive buttons, focus rings, active states, the orb and most chrome. - **Glow**: `--glow` / `--glow-strong` (component stylesheets) and `--shadow-glow` / `--shadow-glow-strong` (glow utilities) hold literal colors, so override them together with the accent. - **Surfaces**: `--bg`, `--surface`, `--surface-raised`, `--border`, `--border-bright`. - **Text**: `--text`, `--text-secondary`, `--text-muted`. - **Status**: `--success`, `--warning`, `--error`. The full list with current values is on [Design tokens](https://joeyash.github.io/jarvis_ui_lib/customization/tokens.md). ## Design rules The look depends on a few rules that the tokens alone do not enforce. Keep them when you build your own components next to the library: - Sharp edges: radius 2px by default, never more than 4px. - Glow instead of drop shadows. - JetBrains Mono everywhere, uppercase labels with letter spacing. - Dark only. There is no light theme. # Design tokens The tokens live in one stylesheet as CSS custom properties on `:root`. The tables below are read from that file at build time, so they always match the installed version. Use them in your own CSS with `var(--name)`. To change them, see [Theming](https://joeyash.github.io/jarvis_ui_lib/customization/theming.md). ### Core palette | Token | Value | Note | | --- | --- | --- | | `--bg` | `#050508` | | | `--surface` | `#0d0d14` | | | `--surface-raised` | `#12121c` | | | `--border` | `#1a1a2e` | | | `--border-bright` | `#2a3d4f` | | ### Blue accent spectrum | Token | Value | Note | | --- | --- | --- | | `--accent` | `#4ca8e8` | orb idle, primary | | `--accent-bright` | `#6ec4ff` | thinking, hover | | `--accent-speak` | `#5ab8f0` | speaking | | `--accent-dim` | `#2d6aa1` | inactive state | ### Text | Token | Value | Note | | --- | --- | --- | | `--text` | `#e8f4ff` | | | `--text-secondary` | `#6b8fa8` | | | `--text-muted` | `#2a3d4f` | | ### Semantic | Token | Value | Note | | --- | --- | --- | | `--warning` | `#e8b24c` | | | `--error` | `#e85a5a` | | | `--success` | `#4ce8a8` | | ### Glow system | Token | Value | Note | | --- | --- | --- | | `--glow` | `0 0 8px #4ca8e8aa` | | | `--glow-strong` | `0 0 20px #4ca8e8cc, 0 0 40px #4ca8e844` | | | `--glow-inner` | `inset 0 0 12px #4ca8e822` | | | `--glow-warn` | `0 0 8px #e8b24caa` | | | `--glow-error` | `0 0 8px #e85a5aaa` | | ### Panel tint | Token | Value | Note | | --- | --- | --- | | `--panel-bg` | `rgba(13, 13, 20, 0.75)` | | | `--panel-blur` | `blur(12px)` | | | `--panel-opacity` | `1` | | ### Type | Token | Value | Note | | --- | --- | --- | | `--font` | `'JetBrains Mono', ui-monospace, Menlo, monospace` | | ### Radii — NEVER exceed these | Token | Value | Note | | --- | --- | --- | | `--r-0` | `0` | | | `--r-1` | `2px` | default | | `--r-2` | `4px` | maximum allowed | ### Spacing | Token | Value | Note | | --- | --- | --- | | `--s-1` | `4px` | | | `--s-2` | `8px` | | | `--s-3` | `12px` | | | `--s-4` | `16px` | | | `--s-5` | `24px` | | | `--s-6` | `32px` | | | `--s-7` | `48px` | | ### Elevation as z-layers | Token | Value | Note | | --- | --- | --- | | `--z-orb` | `0` | | | `--z-panel` | `10` | | | `--z-status` | `20` | | | `--z-topbar` | `30` | | | `--z-dev` | `40` | | | `--z-modal` | `50` | | ### Motion | Token | Value | Note | | --- | --- | --- | | `--ease` | `cubic-bezier(0.4, 0, 0.2, 1)` | | | `--dur-fast` | `120ms` | | | `--dur-base` | `200ms` | | | `--dur-slow` | `300ms` | | | `--dur-ambient` | `1400ms` | | # Tailwind The library is styled with Tailwind v4 internally, but ships compiled CSS. You do not need Tailwind. If your project uses it, you can map the same tokens into your own theme. ## Without Tailwind Nothing to do. `jarvis-react-ui/style.css` contains everything the components need. Write your own styles with the CSS variables: ```css .my-card { background: var(--surface); border: 1px solid var(--border); color: var(--text-secondary); } ``` > **Warning: Don't use the utility classes without Tailwind** > > The stylesheet also contains some Tailwind utility classes (`flex`, `h-[120px]`, ...), but only > the ones the components happen to use internally. They are not part of the public API: most > utilities are missing, and the set changes between releases. Without Tailwind in your project, > do not put utility classes in your own markup. Use [Stack](https://joeyash.github.io/jarvis_ui_lib/components/stack.md) and > [Grid](https://joeyash.github.io/jarvis_ui_lib/components/grid.md) for layout and your own CSS classes with the tokens, as above. The docs demos use Tailwind utilities for their layout (`flex gap-3`, `w-[280px]`, ...). Without Tailwind, replace them with `Stack`, `Grid` or your own CSS when you copy a demo; the component props stay the same. ## With Tailwind v4 Map the tokens in your `@theme` block to get utilities like `bg-surface`, `text-accent` or `border-border` that follow runtime overrides: ```css @import 'tailwindcss'; @theme { --color-bg: var(--bg); --color-surface: var(--surface); --color-border: var(--border); --color-accent: var(--accent); --color-accent-bright: var(--accent-bright); --color-text: var(--text); --color-text-secondary: var(--text-secondary); --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace; } ``` Import `jarvis-react-ui/style.css` before your Tailwind entry. Both stylesheets contain the preflight reset; that is harmless. ## What follows runtime overrides | Kind | Follows overrides | Why | | ------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------ | | Colors (`bg-*`, `text-*`, `border-*`) | Yes | The theme colors point at the CSS variables (set on `:root`, or set the `--color-*` alias on a sub-tree). | | Glow (`shadow-glow*`) | Via `--shadow-glow*` | The utilities read `--shadow-glow*`, not `--glow*`; override both. | | Spacing, z-index, durations | No | Compiled as literal values; use the `--s-*`, `--z-*`, `--dur-*` variables directly where you need runtime control. | | Radius | Fixed | The scale is capped at 2px and 4px by design. | # Stack Lays out its children in a column or a row with spacing from the design tokens. It covers most layout needs without Tailwind, and it is the layout building block for generated windows. ```ts import { Stack } from 'jarvis-react-ui'; ``` ## Column By default the children stack top to bottom and stretch to the full width. `gap` takes a spacing step: `xs` (4px), `sm` (8px), `md` (12px, the default), `lg` (24px), `xl` (32px) or `none`. The steps read the `--s-*` tokens, so they follow a theme. ```tsx import { Button, Label, Metric, Stack } from 'jarvis-react-ui'; export default function Column() { return ( ); } ``` ## Row `direction="row"` lays the children out left to right. `align` sets the cross-axis alignment, `justify` the distribution along the row, and `wrap` lets them flow onto further lines. Stacks nest. ```tsx import { Button, Pill, Stack } from 'jarvis-react-ui'; export default function Row() { return ( online 3 tasks ); } ``` ## Accessibility Stack renders a plain `
` and adds no semantics. Pass `role` or `aria-*` attributes when the group needs them; they reach the root element, and so does the `ref`. ## API | Prop | Type | Default | Description | | --- | --- | --- | --- | | `align` | `'start' \| 'center' \| 'end' \| 'stretch' \| 'baseline'` | `'stretch'` | Alignment across the direction (`align-items`). | | `children` | `ReactNode` | | Content to lay out. | | `className` | `string` | | Additional class names for the root `
`. | | `direction` | `'column' \| 'row'` | `'column'` | Lays the children out in a column (top to bottom) or a row (left to right). | | `gap` | `'none' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Space between the children. | | `justify` | `'start' \| 'center' \| 'end' \| 'between' \| 'around'` | `'start'` | Distribution along the direction (`justify-content`). | | `wrap` | `boolean` | `false` | Lets the children wrap onto further lines. | Also accepts inherited props from `HTMLAttributes` (54), `AriaAttributes` (53), `DOMAttributes` (169), `RefAttributes` (1), `Attributes` (1). # Grid Lays out its children in equal columns with spacing from the design tokens: a fixed number of columns, or as many as fit. ```ts import { Grid } from 'jarvis-react-ui'; ``` ## Fixed columns `columns` takes 1 to 6 equal columns. `gap` uses the same steps as [Stack](https://joeyash.github.io/jarvis_ui_lib/components/stack.md). ```tsx import { Grid, Label, Metric, Stack } from 'jarvis-react-ui'; const READINGS = [ { label: 'CPU', value: 42 }, { label: 'GPU', value: 67 }, { label: 'RAM', value: 58 }, ]; export default function Columns() { return ( {READINGS.map((r) => ( ))} ); } ``` ## Auto-fit With `columns="auto"` (the default) the grid fits as many columns of at least `minColumnWidth` pixels as the width allows, and reflows when it changes, e.g. when a window is resized. On narrower containers a column never gets wider than the container. Like any grid, it fills the width of a block container; inside a flex container (such as a row `Stack`) give it a width. ```tsx import { GlassCard, Grid } from 'jarvis-react-ui'; const SYSTEMS = ['Radar', 'Comms', 'Shields', 'Thrusters', 'Life support', 'Navigation']; export default function Auto() { return ( {SYSTEMS.map((name) => ( nominal ))} ); } ``` ## Accessibility Grid renders a plain `
` with `display: grid` and adds no semantics. The reading order is the order of the children. ## API | Prop | Type | Default | Description | | --- | --- | --- | --- | | `align` | `'start' \| 'center' \| 'end' \| 'stretch'` | `'stretch'` | Vertical alignment of the cells within their row. | | `children` | `ReactNode` | | Cells, one per child. | | `className` | `string` | | Additional class names for the root `
`. | | `columns` | `1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 'auto'` | `'auto'` | Number of equal columns, or `auto` for as many columns of `minColumnWidth` as fit. | | `gap` | `'none' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Space between rows and columns (`--s-*` tokens). | | `minColumnWidth` | `number` | `160` | Minimum column width in px for `columns="auto"`. | Also accepts inherited props from `HTMLAttributes` (54), `AriaAttributes` (53), `DOMAttributes` (169), `RefAttributes` (1), `Attributes` (1). # Button Buttons trigger an action. They come in four variants, two sizes, and play the hover and click sounds of the JARVIS sound set. ```ts import { Button } from 'jarvis-react-ui'; ``` ## Variants Use `primary` for the main action of a view, `secondary` (the default) for regular actions, `ghost` for low-emphasis actions and `danger` for destructive ones. ```tsx import { Button } from 'jarvis-react-ui'; export default function Variants() { return ( <> ); } ``` ## Sizes ```tsx import { Button } from 'jarvis-react-ui'; export default function Sizes() { return ( <> ); } ``` ## Disabled A disabled button is dimmed, cannot be focused by click and does not fire `onClick`. ```tsx import { Button } from 'jarvis-react-ui'; export default function Disabled() { return ( <> ); } ``` ## With an icon Put an icon from `lucide-react` next to the label. Mark it `aria-hidden` because the label already names the action. For icon-only buttons use [IconButton](https://joeyash.github.io/jarvis_ui_lib/components/icon-button.md). ```tsx import { Power, Radar } from 'lucide-react'; import { Button } from 'jarvis-react-ui'; export default function WithIcon() { return ( <> ); } ``` ## Sound Hovering plays `hover_button` and clicking plays `click` through the nearest `SfxProvider`. Without a provider the button stays silent. See [Sound effects](https://joeyash.github.io/jarvis_ui_lib/getting-started/sound.md). ## Accessibility - Renders a native ` ); } ``` ## Toolbar A row of icon buttons with tooltips below them. `delayMs={0}` opens them instantly while the pointer sweeps across the toolbar. ```tsx import { FileCode, Maximize2, Volume2 } from 'lucide-react'; import { IconButton, Tooltip } from 'jarvis-react-ui'; export default function Toolbar() { return (
); } ``` > **Note: Positioning** > > The bubble is absolutely positioned next to the trigger, not portaled. Ancestors with `overflow: > hidden` clip it. ## Accessibility - The bubble has `role="tooltip"` and an id; while it is open the trigger gets `aria-describedby` pointing at it. - It opens on focus and closes on blur and on Escape. - Tooltip content is a supplementary description. Do not put interactive content in it, and do not rely on it as the only accessible name of the trigger (give an `IconButton` its `label`). - `disabled` keeps the tooltip mounted but never shows it. ## API | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` (required) | `ReactElement` | | The trigger: a single element. It receives `aria-describedby` while the tooltip is open. | | `content` (required) | `ReactNode` | | Text or content shown in the tooltip bubble. | | `className` | `string` | | Additional class names for the tooltip bubble (`role="tooltip"`), not the trigger wrapper. | | `delayMs` | `number` | `300` | Delay in ms before the tooltip opens on hover. Keyboard focus opens it immediately. | | `disabled` | `boolean` | `false` | Disables the tooltip without removing it from the tree. | | `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | Side of the trigger the tooltip appears on. | ### Type `TooltipTriggerProps` Props the tooltip injects into its trigger element. | Field | Type | Default | Description | | --- | --- | --- | --- | | `aria-describedby` | `string` | | Id of the tooltip bubble while it is open, so screen readers announce it. | # Divider A hairline that separates content. It runs horizontally or vertically, can fade in the accent color and can carry a small caption. ```ts import { Divider } from 'jarvis-react-ui'; ``` ## Variants `default` uses the border color. `accent` draws a line in the accent color that fades out at both ends. ```tsx import { Divider } from 'jarvis-react-ui'; export default function Variants() { return (
); } ``` ## With a label `label` centers a small uppercase caption in a horizontal divider. Use it to title groups of content. ```tsx import { Divider } from 'jarvis-react-ui'; export default function WithLabel() { return (
); } ``` ## Vertical `orientation="vertical"` stretches to the height of its flex row. Use it to group actions in a toolbar. ```tsx import { Copy, Download, Settings, Trash2 } from 'lucide-react'; import { Divider, IconButton } from 'jarvis-react-ui'; export default function Vertical() { return (
); } ``` ## Accessibility - Renders a `
` with `aria-orientation` set to `horizontal` or `vertical`. - A `label` is plain text inside the separator; it is not a heading. Use a real heading when the caption titles a section. ## API | Prop | Type | Default | Description | | --- | --- | --- | --- | | `className` | `string` | | Additional class names for the root `role="separator"` element (the row when labelled). | | `label` | `ReactNode` | | Optional caption centered in a horizontal divider. | | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direction of the line. A vertical divider stretches to the height of its flex row. | | `variant` | `'default' \| 'accent'` | `'default'` | `accent` draws a fading accent-colored line instead of the border color. | # Pill A small uppercase tag with a hairline border. Use it to show the state of a system, a connection or a task at a glance. ```ts import { Pill } from 'jarvis-react-ui'; ``` ## Variants `default` is neutral. `ok`, `warn` and `err` map to the success, warning and error colors, and `info` uses the bright accent for transient states such as syncing. ```tsx import { Pill } from 'jarvis-react-ui'; export default function Variants() { return ( <> Idle Online Degraded Offline Syncing ); } ``` ## Status list Pair pills with a [Label](https://joeyash.github.io/jarvis_ui_lib/components/label.md) to build a compact status readout. Keep the pill text to one or two words. ```tsx import { Label, Pill } from 'jarvis-react-ui'; const SUBSYSTEMS = [ { name: 'Repulsors', status: 'Armed', variant: 'ok' }, { name: 'Life support', status: 'Nominal', variant: 'ok' }, { name: 'Uplink', status: 'Lagging', variant: 'warn' }, { name: 'Flight control', status: 'Fault', variant: 'err' }, ] as const; export default function StatusList() { return (
    {SUBSYSTEMS.map((s) => (
  • {s.status}
  • ))}
); } ``` ## Accessibility - Renders a plain ``; it has no role and is not focusable. Native attributes (`id`, `title`, `aria-*`, `data-*`) are forwarded to it. - The text is the only status information for screen readers. Do not rely on color alone: the word inside the pill must name the state. - For a status that changes live and must be announced, set `aria-live="polite"` on the pill or wrap the readout in an element with it. ## API | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` (required) | `ReactNode` | | Short status text shown inside the pill; rendered uppercase. | | `className` | `string` | | Additional class names for the root ``. | | `variant` | `'default' \| 'ok' \| 'warn' \| 'err' \| 'info'` | `'default'` | Status color of the text and border: neutral, success, warning, error or accent. | Also accepts inherited props from `HTMLAttributes` (54), `AriaAttributes` (53), `DOMAttributes` (169). # Label A small uppercase caption in the secondary text color. Use it to name a reading, a group of values or a form control. ```ts import { Label } from 'jarvis-react-ui'; ``` ## Captions Put a `Label` above or next to the value it names, such as a [Metric](https://joeyash.github.io/jarvis_ui_lib/components/metric.md). `dim` switches to the muted color for less important captions. ```tsx import { Label, Metric } from 'jarvis-react-ui'; export default function Basic() { return (
); } ``` ## Form controls With `htmlFor`, the label renders as a native `