florixui
v1.15.5
Published
A React component library built on shadcn/ui and Tailwind CSS.
Maintainers
Readme
FlorixUI
A React component library built on shadcn/ui and Tailwind CSS v4. Ships as a bundled npm package (florixui) — install it, import components, import one stylesheet.
A focused set of components is included — shadcn/ui primitives (Alert, Alert Dialog, Badge, Button, Button Group, Calendar, Card, Chart, Checkbox, Command, Dialog, Dropdown Menu, Field, Hover Card, Input, Input Group, Item, Label, Popover, Progress, Radio Group, Select, Separator, Sheet, Slider, Sonner, Spinner, Stepper, Switch, Table, Tabs, Textarea, Timeline, Toggle, Toggle Group, Tooltip), plus custom components (Actions Menu, Advanced Input, Advanced Select, Data Table, Date Time Range Picker, Map) — each documented with live examples in the docs site. Browse them with npm run dev.
Primitives that are app-specific or pull in extra dependencies (Accordion, Aspect Ratio, Avatar, Breadcrumb, Carousel, Collapsible, Context Menu, Drawer, Empty, Form, Input OTP, Kbd, Menubar, Native Select, Navigation Menu, Pagination, Resizable, Scroll Area, Sidebar, Skeleton) are intentionally not bundled — add them directly with npx shadcn@latest add <name> in your app if you need them.
Install (in a consuming project)
npm install florixuireact and react-dom (v18+) are peer dependencies — your app already provides them.
Usage
Import the stylesheet once at your app's entry point, then use components anywhere:
// main.tsx / App entry
import "florixui/styles.css";import { Button } from "florixui";
export function Example() {
return (
<div className="flex gap-3">
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="destructive">Delete</Button>
</div>
);
}The cn() class-merging helper is also exported:
import { cn } from "florixui";Dark mode
The stylesheet defines a .dark variant. Toggle dark mode by adding the dark
class to a root element (e.g. <html class="dark">).
Themes
The package ships 7 themes. Select one by setting data-theme on a root
element; the default (no attribute) is slate-blue. Themes combine with dark
mode:
<html data-theme="crimson" class="dark">| slug | look |
| ------------- | ------------------------------------------ |
| slate-blue | Calm blue on slate (default) · Montserrat |
| crimson | Vivid red · Montserrat |
| terracotta | Warm rust · Montserrat |
| indigo | Bold indigo · Montserrat |
| azure | Bright blue · Montserrat |
| teal | Deep teal · Montserrat |
| argus | ARGUS EcoSystem — neutral greys + teal · Montserrat |
Each theme references specific fonts but the package does not bundle them
(see below) — colors, radius, and shadows all work without the fonts; install
the matching @fontsource package if you want a theme's exact typeface.
Fonts (optional)
To keep styles.css a single self-contained file, fonts are not bundled.
Each theme's font stack falls back to system fonts, so everything works without
them. To render a theme in its true typeface, install the matching
@fontsource package(s) and import them in your app entry. The primary sans
across every theme is Montserrat:
npm install @fontsource-variable/montserratimport "@fontsource-variable/montserrat";Fonts used across the themes: Montserrat (primary sans), Inter, JetBrains Mono, Roboto Mono, DM Sans, DM Serif Text, DM Mono, Merriweather, Noto Serif Georgian.
Developing this library
npm run docs:dev # run the documentation site with HMR (default dev server)
npm run docs:build # build the docs site into dist-docs/
npm run docs:preview # preview the built docs site
npm run build:lib # build the publishable package into dist/
npm run lintDocumentation site
The docs/ directory is a small React app that documents the library. It
imports components straight from source (@/components/...), so examples stay
in sync as you build. Each component page shows a live preview, the
source code (with copy button), a props/API table, and usage notes.
There's a sidebar for navigation and a light/dark theme toggle.
It is not part of the published package — only dist/ is published.
Everything is driven by docs/registry.tsx. To document a new component, add a
ComponentDoc entry there:
// docs/registry.tsx
import { Card } from '@/components/ui/card'
export const components: ComponentDoc[] = [
// ...existing entries
{
slug: 'card',
name: 'Card',
description: 'A container that groups related content.',
usage: <p>Use cards to…</p>,
examples: [
{
name: 'Basic',
render: () => <Card>…</Card>,
code: `<Card>…</Card>`,
},
],
props: [
{ prop: 'className', type: 'string', description: 'Extra classes.' },
],
},
]The sidebar, routing (#/card), and page layout update automatically.
Adding components
Add shadcn components, then export them from src/index.ts and document them
in docs/registry.tsx:
npx shadcn@latest add card input dialog// src/index.ts
export { Card, CardHeader, CardContent } from "@/components/ui/card";Publishing
prepublishOnly runs build:lib automatically, so:
npm version patch
npm publish # add --access public for a public scoped packageOnly the dist/ directory is published (see the files field in package.json).
How it's built
src/index.ts— the package entry; re-exports every public component + util.src/styles.css— the distributable stylesheet;@source "./components"tells Tailwind to scan components so the compiled CSS contains every utility class they use.- Vite library mode (
vite.config.ts, gated onLIB_BUILD) emits the ESM bundle with React externalized, plus.d.tsfiles viavite-plugin-dts.
Components
Auto-generated from the docs registry. Each component below shows a quick usage snippet; run
npm run devfor the full interactive docs (every variant + props table).
Actions Menu
A drop-in "three-dot" overflow menu. Pass a flat list of items (actions, labels, separators) and it renders a kebab-triggered dropdown.
<ActionsMenu
triggerLabel="Open row actions"
items={[
{ label: "Edit", icon: Pencil },
{ label: "Duplicate", icon: Copy },
{ type: "separator" },
{ label: "Delete", icon: Trash2, destructive: true },
]}
/>Advanced Input
A batteries-included input that bundles label, description, icons, affixes, password toggle, loading, error/helper text, a textarea mode, and a multi-value tags mode into one component.
<AdvancedInput
label="Email"
required
type="email"
placeholder="[email protected]"
helperText="We'll never share your email."
description="Used for sign-in and notifications."
/>Advanced Select
A combobox-style select built on Popover + Command with search, multi-select, groups, descriptions, clear, select-all, create-new, infinite scroll, and input-group affixes.
const [value, setValue] = React.useState("")
<AdvancedSelect
options={["Apple", "Banana", "Blueberry", "Grapes", "Pineapple"]}
value={value}
onValueChange={(v) => setValue(v as string)}
placeholder="Pick a fruit"
searchable
clearable
/>Alert
Displays a short, important message that draws attention without interrupting the user.
<Alert>
<Terminal />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components to your app using the CLI.
</AlertDescription>
</Alert>Alert Card
A higher-level alert with two looks — filled (soft tinted background) and outline (bordered card with an icon box and actions) — across four severities. Theme-aware: severities map to the blue / orange / red / green tokens.
<AlertCard
variant="filled"
severity="info"
title="New update"
description="v2.4.0 is ready. Restart to apply."
dismissible
/>Alert Dialog
A modal dialog that interrupts the user with important content and expects a confirm or cancel response before continuing.
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Delete account</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This permanently deletes your account and removes your data from
our servers. This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction variant="destructive">
Delete account
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>Badge
A small label that highlights status, category, or count alongside other content.
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="ghost">Ghost</Badge>
<Badge variant="link">Link</Badge>Button
Triggers an action or event, such as submitting a form or opening a dialog.
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>Button Group
Visually and semantically groups a set of related buttons (or button-like elements) into a single connected control.
<ButtonGroup aria-label="Text alignment">
<Button variant="outline">Left</Button>
<Button variant="outline">Center</Button>
<Button variant="outline">Right</Button>
</ButtonGroup>Calendar
A date field that lets users view a month grid and select a single day, multiple days, or a range.
const [date, setDate] = React.useState<Date | undefined>(new Date())
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-md border"
/>
)Card
A bordered surface that groups related content and actions into a single container.
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>
Deploy your new project in one click.
</CardDescription>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">
Name your project and choose a region to get started.
</p>
</CardContent>
<CardFooter className="justify-end gap-2">
<Button variant="outline">Cancel</Button>
<Button>Deploy</Button>
</CardFooter>
</Card>Card Radio Group
A radio group whose options are bordered cards — each with an optional icon, a label (plus inline sublabel), and a description. The whole card is clickable and the selected card highlights its border.
<CardRadioGroup
defaultValue="mastercard"
items={[
{
value: 'mastercard',
label: 'Mastercard',
sublabel: '(•••• 4242)',
description: 'You can use this card with a label and a description.',
icon: <MastercardIcon />,
},
{
value: 'visa',
label: 'Visa',
sublabel: '(•••• 1881)',
description: 'You can use this card with a label and a description.',
icon: <VisaIcon />,
},
]}
/>Chart
A theming and tooltip/legend wrapper around Recharts that maps a config object to CSS color variables for consistent, accessible charts.
const chartConfig = {
desktop: { label: 'Desktop', color: 'hsl(220 70% 50%)' },
mobile: { label: 'Mobile', color: 'hsl(160 60% 45%)' },
} satisfies ChartConfig
<ChartContainer config={chartConfig} className="min-h-[200px] w-full">
<BarChart accessibilityLayer data={data}>
<CartesianGrid vertical={false} />
<XAxis dataKey="month" tickLine={false} tickMargin={10} axisLine={false} />
<ChartTooltip content={<ChartTooltipContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>Checkbox
A control that lets the user toggle a single option on or off, or select multiple options from a set.
<div className="flex items-center gap-2">
<Checkbox id="terms" />
<label htmlFor="terms" className="text-sm leading-none">
Accept terms and conditions
</label>
</div>Color Picker
A simple color picker: predefined swatches over a color-code input (with a native color field). Controlled via value/onChange; shown as a swatch box or a hex input field.
const [color, setColor] = useState('#9fff5b')
<ColorPicker value={color} onChange={setColor} />Colors
Global semantic accent colors — red, orange, blue, green — each with a foreground pairing and distinct light/dark shades. Independent of the active theme.
<div className="bg-red text-red-foreground">…</div>
<div className="bg-orange text-orange-foreground">…</div>
<div className="bg-blue text-blue-foreground">…</div>
<div className="bg-green text-green-foreground">…</div>Command
A fast, composable command menu with fuzzy search for navigating actions, built on cmdk.
<Command className="max-w-md rounded-lg border shadow-md">
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Suggestions">
<CommandItem>Calendar</CommandItem>
<CommandItem>Search Emoji</CommandItem>
<CommandItem>Calculator</CommandItem>
</CommandGroup>
</CommandList>
</Command>Confirm Prompt
A confirmation dialog for risky actions — mainly deletes. An amber warning icon sits beside the title with a red confirm button, plus an optional type-to-confirm safeguard and async loading support.
const [show, setShow] = useState(false)
<Button variant="destructive" onClick={() => setShow(true)}>
Delete project
</Button>
<ConfirmPrompt
show={show}
onCancel={() => setShow(false)}
onConfirm={() => deleteProject(id)}
title="Delete project?"
message="This action cannot be undone…"
confirmLabel="Delete"
/>Custom Tabs
A higher-level tab strip with two looks — underline and pill — driven by a single items array. Each tab can carry an icon, a numeric count, and a short badge like "New". Built on Radix Tabs for keyboard and a11y support.
const navItems = [
{ value: 'overview', label: 'Overview', icon: <HomeIcon /> },
{ value: 'projects', label: 'Projects', icon: <LayoutPanelTopIcon />, count: 3 },
{ value: 'packages', label: 'Packages', icon: <PackageIcon />, badge: 'New' },
{ value: 'team', label: 'Team', icon: <UsersIcon /> },
]
<CustomTabs type="underline" defaultValue="overview" items={navItems} />Data Table
A simple, column-driven table with the shadcn data-table look: badge cells, row selection (with disableable rows via isRowDisabled), a row-actions menu, and empty/loading states — no sorting/pagination machinery.
const columns: DataTableColumn<Section>[] = [
{ key: "header", header: "Header", cell: (r) => <span className="font-medium">{r.header}</span> },
{ key: "type", header: "Section Type", cell: (r) => <Badge variant="outline">{r.type}</Badge> },
{ key: "status", header: "Status", cell: (r) => <StatusBadge status={r.status} /> },
{ key: "target", header: "Target", align: "right", width: "6rem" },
{ key: "limit", header: "Limit", align: "right", width: "6rem" },
{ key: "reviewer", header: "Reviewer" },
]
<DataTable
data={sections}
columns={columns}
getRowId={(r) => r.id}
selectable
selectedIds={selected}
onSelectionChange={setSelected}
rowActions={(row) => [
{ label: "Edit", icon: Pencil, onSelect: () => edit(row) },
{ type: "separator" },
{ label: "Delete", icon: Trash2, destructive: true, onSelect: () => remove(row) },
]}
/>Date Time Picker
A single date-and-time selector — a trigger that opens a calendar with an H:M:S time row. Controlled via an ISO string. This is the same field the Date Time Range Picker uses for its custom from/to inputs.
const [value, setValue] = useState(new Date().toISOString())
<DateTimePicker value={value} onChange={setValue} label="Starts at" />Date Time Range Picker
A time-range picker with quick presets (hour/day/week/month) and a custom From/To selector — each a calendar plus a precise hour:minute:second time row. Timezone-aware, controlled via ISO strings.
import { DateTimeRangePicker, presetToRange, type TimeRange } from "florixui"
const [range, setRange] = React.useState<TimeRange>({
preset: "day",
...presetToRange("day"),
})
<DateTimeRangePicker value={range} onChange={setRange} />Dialog
A modal window overlaid on the page that interrupts the user to require a response, such as a confirmation or a focused form.
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Open dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Share document</DialogTitle>
<DialogDescription>
Anyone with the link will be able to view this document.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Copy link</Button>
</DialogFooter>
</DialogContent>
</Dialog>Divider
A separator that can carry a label, a count badge, and an icon — with start / center / end label positions, color and thickness variants, and a vertical orientation. For a plain rule, use Separator.
<Divider label="Trigger Settings" labelPosition="start" />
<Divider label="Or continue with" labelPosition="center" />
<Divider label="Section end" labelPosition="end" />Dropdown Menu
Displays a menu of actions or options triggered by a button, built on Radix UI with full keyboard and focus support.
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
Profile
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
Settings
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">
Log out
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Empty
A composable empty state — media (icon/avatar), title, and description in a header, with optional actions. For "no data", "no results", offline, and 404 states.
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<FolderIcon />
</EmptyMedia>
<EmptyTitle>No projects yet</EmptyTitle>
<EmptyDescription>
Get started by creating your first project.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button>
<PlusIcon />
Create project
</Button>
</EmptyContent>
</Empty>Empty State
A convenience wrapper over the Empty primitive — pass icon, title, description, and actions as props (with sensible defaults) instead of composing the parts by hand.
<EmptyState title="No notifications" />Faceted Filter
A controlled filter trigger and popover: a searchable list of options selectable as multi-select checkboxes (default) or single-select. Shows a selected-count badge on the trigger and emits the value(s) via onChange so you can filter your own list or API query.
const [status, setStatus] = useState<string[]>(['backlog', 'todo'])
<FacetedFilter
title="Status"
options={[
{ value: 'backlog', label: 'Backlog', icon: <CircleDashedIcon />, count: 13 },
{ value: 'todo', label: 'Todo', icon: <CircleIcon />, count: 12 },
// ...
]}
value={status}
onChange={setStatus}
/>
// then filter your data:
const filtered = status.length === 0
? tasks
: tasks.filter((t) => status.includes(t.status))Field
Layout primitives that pair a form control with its label, description, and error message in a consistent, accessible structure.
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" type="email" placeholder="[email protected]" />
<FieldDescription>
We'll only use this to send receipts.
</FieldDescription>
</Field>File Upload
A batteries-included drag-and-drop uploader with validation, previews, and two layouts: a single-image dropzone and a multi-file card grid. Backed by the headless useFileUpload hook.
<FileUpload
variant="image"
accept="image/*"
maxSize={5 * 1024 * 1024}
/>Form Dialog
A pre-composed modal for forms: a fixed bordered header (title, description, close button), a scrollable body, and an optional pinned footer for actions. Controlled via open/onClose.
function Example() {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Edit profile</Button>
<FormDialog
open={open}
onClose={() => setOpen(false)}
title="Edit profile"
description="Update your details. Changes are saved when you submit."
footer={
<>
<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
<Button onClick={() => setOpen(false)}>Save changes</Button>
</>
}
>
<form className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>
<Input id="name" defaultValue="Ada Lovelace" />
</div>
<div className="grid gap-2">
<Label htmlFor="bio">Bio</Label>
<Textarea id="bio" rows={4} />
</div>
</form>
</FormDialog>
</>
)
}Hover Card
Shows rich preview content in a floating card when the user hovers over or focuses a trigger.
<HoverCard>
<HoverCardTrigger asChild>
<Button variant="link">@shadcn</Button>
</HoverCardTrigger>
<HoverCardContent>
<p className="font-medium">@shadcn</p>
<p className="text-muted-foreground">
Creator of the component library. Hover to learn more.
</p>
</HoverCardContent>
</HoverCard>Input
A single-line text field for collecting short, free-form user input such as names, emails, or passwords.
<Input type="text" placeholder="Enter your name" />Input Group
Wraps an input or textarea with aligned addons such as icons, text, or buttons to form a single composed control.
<InputGroup className="max-w-sm">
<InputGroupAddon>
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="example.com" />
</InputGroup>Item
A flexible row for displaying a piece of content with optional media, title, description, and actions.
<Item variant="outline" className="max-w-md">
<ItemMedia variant="icon">
<svg viewBox="0 0 24 24" aria-hidden="true">
<circle cx="12" cy="12" r="10" fill="currentColor" />
</svg>
</ItemMedia>
<ItemContent>
<ItemTitle>Project Atlas</ItemTitle>
<ItemDescription>Updated 3 minutes ago by Dana.</ItemDescription>
</ItemContent>
<ItemActions>
<Button variant="outline" size="sm">Open</Button>
</ItemActions>
</Item>Label
Renders an accessible caption for a form control, associating text with an input via htmlFor.
<div className="grid w-full max-w-sm gap-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="[email protected]" />
</div>List Card
A minimal content card for list and grid layouts. A top row (badge + meta), an optional media thumbnail beside a title and description, a footer, and a corner actions menu — every slot is optional, so it renders any kind of data.
<ListCardGrid columns={3}>
{alerts.map((a) => (
<ListCard
key={a.id}
badge={a.badge}
title={a.title}
description={a.description}
media={a.imageUrl}
meta={<><ClockIcon className="size-3" /> 10:12 AM</>}
actions={[
{ label: 'View details', icon: EyeIcon },
{ label: 'Mark as safe', icon: CheckIcon },
{ type: 'separator' },
{ label: 'Archive', icon: ArchiveIcon, destructive: true },
]}
footer={
<>
<ListCardPerson name={a.person} />
<ListCardChip icon={<TruckIcon />}>{a.entity}</ListCardChip>
</>
}
/>
))}
</ListCardGrid>Map
An interactive map built on MapLibre GL (via mapcn), with markers, routes, clustering, and overlays. Uses a free CARTO light basemap by default with no attribution — no API key required.
<Map
viewport={{ center: [-122.4194, 37.7749], zoom: 10 }}
className="h-[360px] w-full rounded-lg border"
/>Not Found
A centered status screen — a large code (e.g. "404"), a title, a description, and Go Back / Go to Home actions. Generic enough for 404 / 403 / 500 and empty states.
<NotFound homeHref="/" />Popover
Displays rich, floating content in a portal, anchored to a trigger and toggled by click.
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open popover</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Dimensions</PopoverTitle>
<PopoverDescription>
Set the size for the selected layer.
</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>Progress
Displays an indicator showing the completion progress of a task, such as a download or upload.
<Progress value={60} aria-label="Loading" />Radio Group
A set of checkable buttons where no more than one can be selected at a time.
<RadioGroup defaultValue="comfortable">
<div className="flex items-center gap-2">
<RadioGroupItem value="default" id="r1" />
<Label htmlFor="r1">Default</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="comfortable" id="r2" />
<Label htmlFor="r2">Comfortable</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="compact" id="r3" />
<Label htmlFor="r3">Compact</Label>
</div>
</RadioGroup>Select
Displays a list of options for the user to pick from, triggered by a button.
<Select>
<SelectTrigger className="w-48">
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectItem value="apple">Apple</SelectItem>
<SelectItem value="banana">Banana</SelectItem>
<SelectItem value="blueberry">Blueberry</SelectItem>
<SelectItem value="grapes">Grapes</SelectItem>
</SelectContent>
</Select>Sensor Card
A compact info/action card with a left side (icon, mode label, description) and a right side (accent bar + value). Tint it with colorVariant, wrap it with variant, and wire onClick / onValueClick for actions.
<SensorCard
variant="standalone"
icon={<BlindsIcon className="size-5 text-primary" />}
mode="Shades & Curtains"
description="shade 01"
value="Active"
showAccent
valueColorVariant="primary"
/>Separator
Visually or semantically divides content, either horizontally or vertically.
<div className="w-full max-w-sm">
<div className="space-y-1">
<h4 className="text-sm font-medium leading-none">Radix Primitives</h4>
<p className="text-sm text-muted-foreground">
An open-source UI component library.
</p>
</div>
<Separator className="my-4" />
<p className="text-sm text-muted-foreground">Built with care.</p>
</div>Sheet
A panel that slides in from an edge of the screen to show supplementary content or actions without leaving the current page.
<Sheet>
<SheetTrigger asChild>
<Button variant="outline">Open sheet</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<SheetFooter>
<SheetClose asChild>
<Button>Save changes</Button>
</SheetClose>
<SheetClose asChild>
<Button variant="outline">Cancel</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>Side Sheet
A slide-in panel with a pinned header and a sticky footer — the header and footer stay fixed while the body scrolls between them. Ideal for long configuration forms. Controlled via open/onClose.
function Example() {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Open configuration</Button>
<SideSheet
open={open}
onClose={() => setOpen(false)}
onBack={() => setOpen(false)}
floating
title="PID Equation Program Configuration"
footer={
<>
<Button onClick={() => setOpen(false)}>Save</Button>
<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
</>
}
>
<AdvancedInput label="Program name" placeholder="Enter program name" required />
<AdvancedSelect label="PID Equation Type" required options={EQUATION_TYPES} />
<SideSheetSection label="Reading VS Target Settings">
<div className="grid grid-cols-2 gap-4">
<AdvancedSelect label="Reading Source" options={SOURCES} />
<AdvancedSelect label="Target Source" options={SOURCES} />
</div>
</SideSheetSection>
</SideSheet>
</>
)
}Slider
Lets users select a value or range from a continuous track by dragging one or more thumbs.
<Slider defaultValue={[50]} max={100} step={1} className="w-72" />Sonner
An opinionated toast notification system for surfacing brief, non-blocking feedback.
import { toast } from "sonner"
import { Toaster } from "@/components/ui/sonner"
import { Button } from "@/components/ui/button"
// Render <Toaster /> once near your app root.
<Toaster />
<Button
variant="outline"
onClick={() => toast("Your changes have been saved")}
>
Show toast
</Button>Spinner
An animated loading indicator that communicates that content or an action is in progress.
<Spinner />Stat Card
A dashboard metric card with a title, a bold value, and an optional accessory — a tinted icon, a colored trend delta, a linear progress bar, a sparkline area chart, or a radial ring.
<StatCard
title="Total Revenue"
value="$45,231"
description="+20.1% from last month"
icon={<DollarSignIcon />}
color="danger"
/>Stepper
A composable stepper (from Origin UI) for multi-step flows — horizontal or vertical, with numbered indicators, titles, descriptions, and an active/completed state.
<Stepper defaultValue={2}>
{steps.map(({ step, title, description }) => (
<StepperItem key={step} step={step} className="relative flex-1 flex-col!">
<StepperTrigger className="flex-col gap-3 rounded">
<StepperIndicator />
<div className="space-y-0.5 px-2">
<StepperTitle>{title}</StepperTitle>
<StepperDescription className="max-sm:hidden">{description}</StepperDescription>
</div>
</StepperTrigger>
{step < steps.length && (
<StepperSeparator className="-order-1 absolute inset-x-0 top-3 left-[calc(50%+0.75rem+0.125rem)] m-0 -translate-y-1/2 group-data-[orientation=horizontal]/stepper:w-[calc(100%-1.5rem-0.25rem)] group-data-[orientation=horizontal]/stepper:flex-none" />
)}
</StepperItem>
))}
</Stepper>Switch
A toggle control that lets the user switch a single setting on or off, applying the change immediately.
<div className="flex items-center gap-2">
<Switch id="airplane" defaultChecked />
<Label htmlFor="airplane">Airplane mode</Label>
</div>Table
Displays tabular data in rows and columns, composed from semantic header, body, footer, and caption parts.
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Role</TableHead>
<TableHead className="text-right">Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-medium">Ada Lovelace</TableCell>
<TableCell>Engineer</TableCell>
<TableCell className="text-right">Active</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">Alan Turing</TableCell>
<TableCell>Researcher</TableCell>
<TableCell className="text-right">Active</TableCell>
</TableRow>
</TableBody>
</Table>Tabs
A set of layered sections of content (tab panels) where only one panel is shown at a time.
<Tabs defaultValue="account" className="w-[360px]">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">
<p className="text-muted-foreground">Make changes to your account here.</p>
</TabsContent>
<TabsContent value="password">
<p className="text-muted-foreground">Change your password here.</p>
</TabsContent>
</Tabs>Textarea
A multi-line text input for longer free-form content such as comments, descriptions, or messages.
<Textarea placeholder="Type your message here." />Timeline
A composable timeline (from Origin UI) for sequences of events — vertical or horizontal, with active/completed state, icon or avatar indicators, and an alternating layout.
<Timeline defaultValue={3}>
{items.map((item) => (
<TimelineItem key={item.id} step={item.id}
className="group-data-[orientation=vertical]/timeline:ms-10">
<TimelineHeader>
<TimelineSeparator className="group-data-[orientation=vertical]/timeline:-left-7 group-data-[orientation=vertical]/timeline:h-[calc(100%-1.5rem-0.25rem)] group-data-[orientation=vertical]/timeline:translate-y-6.5" />
<TimelineTitle className="mt-0.5">{item.title}</TimelineTitle>
<TimelineIndicator className="flex size-6 items-center justify-center border-none bg-primary/10 group-data-completed/timeline-item:bg-primary group-data-completed/timeline-item:text-primary-foreground group-data-[orientation=vertical]/timeline:-left-7">
<item.icon size={14} />
</TimelineIndicator>
</TimelineHeader>
<TimelineContent>
{item.description}
<TimelineDate className="mt-2 mb-0">{item.date}</TimelineDate>
</TimelineContent>
</TimelineItem>
))}
</Timeline>Toggle
A two-state button that can be either on or off, toggling the active state when pressed.
<Toggle aria-label="Toggle bold">
<Bold />
</Toggle>Toggle Group
A set of two-state buttons that can be toggled on or off, supporting single or multiple selection.
<ToggleGroup type="single" defaultValue="center" variant="outline">
<ToggleGroupItem value="left" aria-label="Align left">
Left
</ToggleGroupItem>
<ToggleGroupItem value="center" aria-label="Align center">
Center
</ToggleGroupItem>
<ToggleGroupItem value="right" aria-label="Align right">
Right
</ToggleGroupItem>
</ToggleGroup>Tooltip
Displays a brief, contextual label in a popup when the user hovers or focuses an element.
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover me</Button>
</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>Bits
Small, composable building blocks (see the "Bits" page in the docs). Each shows a quick usage snippet.
Card in card
An outer card with a header + action, containing nested cards — one per Card background variant.
// One nested card per Card variant
const SITES = [
{ variant: 'alt', name: 'Skyline Tower', /* … */ },
{ variant: 'primary', name: 'Marina Heights', /* … */ },
{ variant: 'success', name: 'Green Park Plaza', /* … */ },
{ variant: 'warning', name: 'Dockside Depot', /* … */ },
{ variant: 'danger', name: 'Old Mill Unit', /* … */ },
]
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Building2Icon className="size-5" /> Site Assignment
</CardTitle>
<CardDescription>Nested cards, one per variant</CardDescription>
<CardAction>
<Button variant="outline" size="sm">
<ArrowLeftRightIcon className="size-4" /> Reassign
</Button>
</CardAction>
</CardHeader>
<CardContent className="grid gap-3 sm:grid-cols-2">
{SITES.map((s) => (
<Card key={s.name} variant={s.variant} size="sm">
<CardContent className="flex items-center gap-3">
<StatusIcon className="bg-card text-foreground"><Building2Icon /></StatusIcon>
<div className="flex-1">
<p className="font-medium">{s.name}</p>
<p className="text-xs text-muted-foreground">
<LayersIcon className="size-3.5" /> {s.floor}
</p>
<p className="text-xs text-muted-foreground">
<MapPinIcon className="size-3.5" /> {s.addr}
</p>
</div>
<Badge>{s.status}</Badge>
</CardContent>
</Card>
))}
</CardContent>
</Card>DataCell
A labelled value cell. "stacked" (default) puts the label above the value — lay them out in a grid for spec sheets; "row" puts the value on the right.
// stacked (default) — an optional icon sits beside the value
<div className="grid grid-cols-3 gap-x-8 gap-y-4">
<DataCell label="Make" value="Liebherr" />
<DataCell label="Category" value="lifting" icon={<WrenchIcon />} />
<DataCell label="Asset Value" value="₹4,500,000" icon={<BanknoteIcon />} />
{/* … */}
</div>
// row — value (with icon) on the right
<div className="divide-y">
<DataCell layout="row" icon={<BanknoteIcon />} label="Asset Value" value="₹4,500,000" />
<DataCell layout="row" icon={<ShieldCheckIcon />} label="Insurance Policy" value="INS-CR-8821" />
</div>DefRow
A label/value definition row for detail cards. Stack several in a divide-y container.
<div className="divide-y">
<DefRow label="Price" value="$960.99" />
<DefRow label="Stock" value="5 units" />
<DefRow label="Category" value="Electronics" />
<DefRow label="SKU" value="SKU-RCH45Q1A" />
</div>MapMarkerPin
A reusable map-marker visual: a colored pin with an icon, an optional pulsing halo + scale when active, and an optional label. Pass icon, color, and active state. Drop inside a MapMarker.
// Inside a <MapMarker longitude={...} latitude={...}>:
<MapMarkerPin icon={<NavigationIcon />} color="bg-green" />
// Active = pulsing halo + scale-up + label, with a rotated icon:
<MapMarkerPin
icon={<NavigationIcon />}
color="bg-primary"
rotate={45}
active
label="LH-105 · A. Singh"
/>QuickStat
A compact inline stat — icon, value, and an optional muted label. Line several up with vertical separators.
<div className="flex items-center gap-3 [&>[data-slot=separator]]:h-4">
<QuickStat icon={<TagIcon />} value="$960.99" />
<Separator orientation="vertical" />
<QuickStat icon={<PackageIcon />} value={5} label="in stock" />
<Separator orientation="vertical" />
<QuickStat icon={<StarIcon className="fill-orange text-orange" />} value={4.9} />
<Separator orientation="vertical" />
<QuickStat icon={<TrendingUpIcon />} value={982} label="sold" />
</div>StatusList
Status rows with flexible leading visuals (tinted icon box, avatar/initials, or plain icon), pill / outline / text status, and group headers.
<StatusList>
<StatusListGroup label="Gateways" count={2}>
<StatusListItem
media={<StatusIcon tone="success"><RadioIcon /></StatusIcon>}
title="GW-SKY-B01"
description="WiFi · 100% · 2 tags"
status="Online"
statusVariant="outline"
tone="success"
/>
<StatusListItem
media={<StatusIcon tone="warning"><RadioIcon /></StatusIcon>}
title="GW-SKY-B04"
description="4G · 54% · 2 tags"
status="Degraded"
statusVariant="outline"
tone="warning"
/>
</StatusListGroup>
<StatusListGroup label="Workers" count={2}>
<StatusListItem
media={<StatusAvatar name="Arjun Das" tone="primary" />}
title="Arjun Das"
description="Electrician"
status="Active"
statusVariant="text"
tone="success"
/>
<StatusListItem
media={<StatusAvatar name="Fatima Sheikh" tone="primary" />}
title="Fatima Sheikh"
description="Safety Officer"
status="Active"
statusVariant="text"
tone="success"
/>
</StatusListGroup>
</StatusList>Thumbnail (inline)
A square image with an icon fallback when no src is provided — for record headers and lists.
function Thumb({ src, alt }: { src?: string; alt: string }) {
return (
<div className="flex size-14 shrink-0 items-center justify-center overflow-hidden rounded-lg border bg-muted">
{src ? (
<img src={src} alt={alt} className="size-full object-cover" />
) : (
<ImageIcon className="size-6 text-muted-foreground" />
)}
</div>
)
}