Component Reference
This is the canonical API reference for StyleLab UI. Each section describes a component’s purpose, props (with types), and a working example. Use it when implementing features or when an AI needs accurate usage details. All components require ThemeProvider and the @raxrai/stylelab-ui/styles import — see Installation & Theming.
Global
Types, context, and utilities shared across the library. Import from @raxrai/stylelab-ui.
Themes
- StyleLabTheme — Union:
"minimal" | "night" | "glass" | "neubrutal" | "clay" | "cyberpunk" | "retro" | "motion" - THEMES — Readonly array of all theme values (for dropdowns and validation)
Context
- ThemeProvider —
defaultTheme?: StyleLabTheme,children: ReactNode. Wrap your app so components receive the active theme. - useTheme() — Returns
{ theme: StyleLabTheme, setTheme: (theme) => void }. Use inside a provider.
Utilities
- cn(...inputs) — Merges class names (Tailwind-aware). Accepts strings, objects, arrays.
- getThemeClass(theme, component, variant?) — Returns the theme-specific class string for a given component and optional variant. Use when building custom components that follow StyleLab themes.
- getNextListIndex(current, direction, length) — Returns the next index for list keyboard nav (
direction: "up" | "down").
Accordion
A set of expandable panels. Only one panel is open at a time by default; set allowMultiple to true for multiple open panels. Each item has a unique id, a title (clickable header), and content (body).
When to use: FAQs, product details, or any collapsible sections where you have a list of title + content pairs.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
| items | AccordionItem[] | Yes | Array of { id, title: ReactNode, content: ReactNode } |
| allowMultiple | boolean | No | If true, multiple panels can be open at once. Default: false. |
| className | string | No | Additional CSS classes for the container. |
| theme | StyleLabTheme | No | Override the context theme for this component. |
Example
import { Accordion } from "@raxrai/stylelab-ui";
<Accordion
items={[
{ id: "1", title: "Section 1", content: <p>Content here.</p> },
{ id: "2", title: "Section 2", content: <p>More content.</p> },
]}
allowMultiple={false}
/>Notes
- ·AccordionItem.title and content can be React nodes (strings, elements, or fragments).
- ·Supports theme prop for per-instance styling.
Alert
An inline alert or callout box. Use the intent prop to get the right semantic styling (info, success, warning, danger). Renders as a div with role='alert' by default.
When to use: Form errors, success messages, warnings, or informational banners above or below content.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
| intent | "default" | "info" | "success" | "warning" | "danger" | No | Visual and semantic variant. Default: "default". |
| title | ReactNode | No | Optional heading above the alert body. |
| children | ReactNode | No | Main alert message or content. |
| className | string | No | Additional CSS classes. |
| theme | StyleLabTheme | No | Override theme for this instance. |
Example
import { Alert } from "@raxrai/stylelab-ui";
<Alert intent="warning" title="Heads up">
This action cannot be undone.
</Alert>
<Alert intent="success">Saved successfully.</Alert>Notes
- ·Supports standard div HTML attributes (e.g. role, aria-*).
Avatar & AvatarGroup
Avatar shows a user's image or initials in a circle. When no image is provided, use fallback (e.g. initials "JD") or alt text (initials are derived from alt). AvatarGroup stacks multiple avatars and shows a +N badge when there are more than max.
When to use: User profiles, comment authors, team lists, or anywhere you need a compact user identity.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
| Avatar: src | string | null | No | Image URL. When null/undefined, fallback or alt is used. |
| Avatar: alt | string | No | Accessible description; also used to derive initials when no fallback. |
| Avatar: fallback | string | No | Shown when no image (e.g. initials). Overrides derived initials from alt. |
| AvatarGroup: children | ReactNode | Yes | One or more Avatar elements. |
| AvatarGroup: max | number | No | Max avatars to show before +N. Default: 4. |
| theme | StyleLabTheme | No | Both support theme override. |
Example
import { Avatar, AvatarGroup } from "@raxrai/stylelab-ui";
<Avatar src="/user.jpg" alt="Jane Doe" />
<Avatar fallback="JD" />
<AvatarGroup max={3}>
<Avatar fallback="A" /><Avatar fallback="B" /><Avatar fallback="C" /><Avatar fallback="D" />
</AvatarGroup>Notes
- ·Avatar forwards a ref to the root div.
- ·AvatarGroup wraps children in a flex container with overlap styling.
Badge
Small label or status pill. Renders as a span. Use variant for semantic color and dot for a leading indicator.
Props
- ·variant?: "default" | "success" | "warning" | "error"
- ·dot?: boolean — show a small dot before the label
- ·children: ReactNode — badge text
- ·className?, theme?
Example
import { Badge } from "@raxrai/stylelab-ui";
<Badge>New</Badge>
<Badge variant="success" dot>Active</Badge>BentoGrid
A grid container for bento-style layouts. You control the grid via className (e.g. grid-cols-3 gap-4). Children are rendered inside the grid.
Props
- ·children: ReactNode
- ·className?: string
Example
import { BentoGrid } from "@raxrai/stylelab-ui";
<BentoGrid className="grid-cols-3 gap-4">
<div>...</div><div>...</div><div>...</div>
</BentoGrid>Calendar
Single-date picker. Use controlled mode (value + onSelect) or uncontrolled (defaultValue). Optional min / max constrain selectable dates.
Props
- ·value?: Date | null — controlled selected date
- ·defaultValue?: Date | null — initial date (uncontrolled)
- ·onSelect?: (date: Date) => void — called when user selects a date
- ·min?: Date, max?: Date — date range bounds
- ·className?, theme?
Example
import { Calendar } from "@raxrai/stylelab-ui";
<Calendar defaultValue={new Date()} onSelect={(d) => console.log(d)} />
<Calendar value={selected} onSelect={setSelected} min={new Date()} />Card
Content container with optional header and footer slots. Use padding to control inner spacing and isHoverable for hover styling.
Props
- ·padding?: "none" | "sm" | "md"
- ·isHoverable?: boolean — adds hover lift/shadow
- ·header?: ReactNode, footer?: ReactNode
- ·children: ReactNode — main body
- ·className?, theme?
Example
import { Card } from "@raxrai/stylelab-ui";
<Card header="Title" footer={<Button>Action</Button>}>
Body content
</Card>CommandPalette
A modal command palette (e.g. ⌘K). The list is filterable by typing; each item has id, label, and onSelect. Optional shortcut is shown on the right. Keyboard: Arrow keys, Enter to run, Escape to close.
Props
- ·open: boolean — visibility
- ·onClose: () => void — called on Escape or overlay click
- ·commands: CommandItem[] (required). Each: { id: string, label: string, shortcut?: string, onSelect: () => void }
- ·placeholder?: string — input placeholder. Default: "Type a command..."
- ·theme?
Example
import { CommandPalette } from "@raxrai/stylelab-ui";
<CommandPalette
open={open}
onClose={() => setOpen(false)}
commands={[
{ id: "1", label: "New file", onSelect: () => {} },
{ id: "2", label: "Save", shortcut: "⌘S", onSelect: () => {} },
]}
placeholder="Type a command..."
/>DashboardShell
Full dashboard layout with sidebar navigation, main content area, optional admin nav, and user menu (email, role, logout). Pass currentPath to highlight the active nav item. When userRole is "ADMIN", adminNavItems are shown.
Props
- ·children: ReactNode
- ·navItems: { href: string, label: string }[] (required)
- ·adminNavItems?: { href: string, label: string }[]
- ·currentPath?: string (highlights active item)
- ·userEmail?: string, userRole?: string ("ADMIN" shows adminNavItems)
- ·onLogout?: () => void
- ·logo?: ReactNode
- ·className?
Example
import { DashboardShell } from "@raxrai/stylelab-ui";
<DashboardShell
navItems={[{ href: "/", label: "Home" }, { href: "/settings", label: "Settings" }]}
currentPath={pathname}
userEmail="u@example.com"
onLogout={() => {}}
>
<main>Page content</main>
</DashboardShell>DataTable
Generic table: define columns (key, header, optional custom render) and data array. Use getRowKey for stable keys when rows can change.
Props
- ·columns: Column<T>[] (required). Column: { key: keyof T | string, header: string, render?: (row: T) => ReactNode }
- ·data: T[] (required)
- ·getRowKey?: (row: T, index: number) => string | number
- ·className?
Example
import { DataTable } from "@raxrai/stylelab-ui";
<DataTable
columns={[
{ key: "name", header: "Name" },
{ key: "email", header: "Email", render: (r) => r.email },
]}
data={[{ name: "Jane", email: "j@x.com" }]}
getRowKey={(r) => r.email}
/>DocumentAccordion
A single expandable section with title and content. When pdfUrl is provided, an inline PDF viewer is shown with an “Open PDF” link. Use defaultOpen to start expanded.
Props
- ·title: ReactNode (required)
- ·content?: ReactNode
- ·pdfUrl?: string
- ·defaultOpen?: boolean
- ·className?, theme?
Example
import { DocumentAccordion } from "@raxrai/stylelab-ui";
<DocumentAccordion title="Syllabus" content="<p>Rich text...</p>" />
<DocumentAccordion title="PDF" pdfUrl="/doc.pdf" defaultOpen />Dropdown
A trigger element that opens a menu of items. Control selection with value / onValueChange (controlled) or defaultValue. Each item has value, label, and optional disabled.
Props
- ·trigger: ReactNode (required)
- ·items: DropdownItem[] (required). DropdownItem: { value: string, label: ReactNode, disabled?: boolean }
- ·value?: string (controlled), defaultValue?: string
- ·onValueChange?: (value: string) => void
- ·className?, theme?
Example
import { Dropdown } from "@raxrai/stylelab-ui";
<Dropdown
trigger={<button>Open</button>}
items={[
{ value: "a", label: "Option A" },
{ value: "b", label: "Option B", disabled: true },
]}
onValueChange={(v) => setValue(v)}
/>Flashcard
A flip card: one side shows the question, the other the answer. User interaction flips between them. Use for quizzes or learning UIs.
Props
- ·question: string (required)
- ·answer: string (required)
- ·className?: string
Example
import { Flashcard } from "@raxrai/stylelab-ui";
<Flashcard question="What is 2+2?" answer="4" />GraphicCard
A card with emphasis styling (e.g. gradient, shadow) for hero sections or feature callouts. Content is passed as children.
Props
- ·children: ReactNode
- ·className?: string
Example
import { GraphicCard } from "@raxrai/stylelab-ui";
<GraphicCard><p>Highlighted content</p></GraphicCard>Input
Text input with optional label, error, helperText, and prefix / suffix. Forwards ref to the native input. Supports all standard input attributes (placeholder, value, onChange, disabled, etc.); the component’s size overrides the HTML size attribute.
Props
- ·size?: "sm" | "md" | "lg"
- ·label?: string
- ·error?: string, helperText?: string
- ·prefix?: ReactNode, suffix?: ReactNode
- ·className?, theme?
- ·Plus standard input HTML attributes (placeholder, value, onChange, disabled, etc.). Component size overrides HTML size.
Example
import { Input } from "@raxrai/stylelab-ui";
<Input label="Email" placeholder="you@example.com" />
<Input label="Name" error="Required" />Modal
Dialog overlay with backdrop. Control visibility with open and onClose. Optional title and size (sm | md | lg). Content is passed as children.
Props
- ·open: boolean, onClose: () => void (required)
- ·title?: string
- ·size?: "sm" | "md" | "lg"
- ·children?: ReactNode
- ·className?, theme?
Example
import { Modal } from "@raxrai/stylelab-ui";
<Modal open={open} onClose={() => setOpen(false)} title="Confirm">
<p>Are you sure?</p>
<Button onClick={() => setOpen(false)}>OK</Button>
</Modal>PricingCard
A card for a pricing tier. Pass a tier object: name, price, description, features array, cta label, and optional highlighted. Use onSelect when the user clicks the CTA.
Props
- ·tier: Tier (required). Tier: { name: string, price: string, description?: string, features: string[], cta: string, highlighted?: boolean }
- ·onSelect?: () => void
- ·className?
Example
import { PricingCard } from "@raxrai/stylelab-ui";
<PricingCard
tier={{
name: "Pro",
price: "$20/mo",
features: ["Feature 1", "Feature 2"],
cta: "Get started",
highlighted: true,
}}
onSelect={() => {}}
/>ProgressBar
Progress indicator. Fill is determined by value / max (max defaults to 100). Use segmented for a step-style bar.
Props
- ·value: number (required)
- ·max?: number (default 100)
- ·segmented?: boolean
- ·className?
Example
import { ProgressBar } from "@raxrai/stylelab-ui";
<ProgressBar value={60} />
<ProgressBar value={7} max={10} segmented />SectionHeader
Section title with optional subtitle and a bottom border. Content is prop-based only (no children). Use for page or section headings.
Props
- ·title: string (required)
- ·subtitle?: string
- ·className?
- ·style?
Example
import { SectionHeader } from "@raxrai/stylelab-ui";
<SectionHeader title="Getting started" subtitle="Follow these steps." />Skeleton
Loading placeholder with a subtle shimmer. Use variant to match the shape of the content (rectangle, circle, or text line).
Props
- ·variant?: "rectangle" | "circle" | "text"
- ·className?, theme?
- ·Plus standard div attributes
Example
import { Skeleton } from "@raxrai/stylelab-ui";
<Skeleton />
<Skeleton variant="circle" className="size-10" />
<Skeleton variant="text" className="w-32" />Slider
Numeric range input. Controlled: value + onValueChange. Uncontrolled: defaultValue. Supports min, max, step, and size.
Props
- ·size?: "sm" | "md" | "lg"
- ·min?: number, max?: number, step?: number
- ·value?: number (controlled), defaultValue?: number
- ·onValueChange?: (value: number) => void
- ·className?, theme?
Example
import { Slider } from "@raxrai/stylelab-ui";
<Slider min={0} max={100} defaultValue={50} onValueChange={setValue} />StatsCard
A small card for a single metric: label (e.g. “Revenue”), value (number or string), and optional trend (direction up/down and value string like “+8%”).
Props
- ·label: string, value: string | number (required)
- ·trend?: { direction: "up" | "down", value: string }
- ·className?
Example
import { StatsCard } from "@raxrai/stylelab-ui";
<StatsCard label="Revenue" value="$12k" trend={{ direction: "up", value: "+8%" }} />Tabs
Tabbed UI: each item has label, value, and content. Use value / onValueChange (controlled) or defaultValue.
Props
- ·items: TabItem[] (required). TabItem: { label: string, value: string, content: ReactNode }
- ·value?: string, defaultValue?: string
- ·onValueChange?: (value: string) => void
- ·className?, theme?
Example
import { Tabs } from "@raxrai/stylelab-ui";
<Tabs
items={[
{ label: "Tab A", value: "a", content: <p>A</p> },
{ label: "Tab B", value: "b", content: <p>B</p> },
]}
defaultValue="a"
/>Terminal
Terminal-style block for commands or log output. Optional title (e.g. “bash”); children are the content inside the terminal.
Props
- ·title?: string
- ·children: ReactNode
- ·className?: string
Example
import { Terminal } from "@raxrai/stylelab-ui";
<Terminal title="bash">
<span>$ npm install @raxrai/stylelab-ui</span>
</Terminal>Timeline
Vertical timeline. Each item has title (required) and optional description and time. Good for activity feeds or step lists.
Props
- ·items: TimelineItem[] (required). TimelineItem: { title: ReactNode, description?: ReactNode, time?: ReactNode }
- ·className?, theme?
Example
import { Timeline } from "@raxrai/stylelab-ui";
<Timeline
items={[
{ title: "Step 1", description: "Done", time: "10:00" },
{ title: "Step 2", time: "11:00" },
]}
/>Toast
Dismissible toast notification. Content is via message; onDismiss is called when the user closes it. No children; use for transient feedback.
Props
- ·message: string (required)
- ·onDismiss: () => void (required)
- ·className?
- ·style?
Example
import { Toast } from "@raxrai/stylelab-ui";
<Toast message="Saved successfully." onDismiss={() => setVisible(false)} />Toggle
Checkbox-style toggle switch. Controlled: checked + onCheckedChange. Uncontrolled: defaultChecked. Forwards ref to the input.
Props
- ·checked?: boolean, defaultChecked?: boolean
- ·onCheckedChange?: (checked: boolean) => void
- ·className?, theme?
- ·Plus standard input attributes except value, type, onChange, size
Example
import { Toggle } from "@raxrai/stylelab-ui";
<Toggle checked={on} onCheckedChange={setOn} />
<Toggle defaultChecked />Tooltip
Shows content on hover over the trigger (children). Use placement to control where the tooltip appears (top, bottom, left, right).
Props
- ·content: ReactNode (required)
- ·children: ReactNode (required) — trigger element
- ·placement?: "top" | "bottom" | "left" | "right"
- ·className?, theme?
Example
import { Tooltip } from "@raxrai/stylelab-ui";
<Tooltip content="Save the document" placement="top">
<button>Save</button>
</Tooltip>Hooks
Utility hooks for focus management, click-outside, and keyboard navigation. Import from @raxrai/stylelab-ui.
Reference
- ·useFocusTrap(active: boolean, options?: { returnFocus?: boolean }): RefObject<HTMLElement | null> — attach ref to container to trap focus
- ·useClickOutside(ref | ref[], handler: (e) => void, options?: { enabled?: boolean }): void — run handler when click is outside ref(s)
- ·useKeyboardNavigation({ onEscape?, onArrowDown?, onArrowUp?, onArrowLeft?, onArrowRight?, enabled? }): void — attach to container for arrow/escape handling
- ·getNextListIndex(current: number, direction: "up" | "down", length: number): number — for list keyboard nav