Import path:
import { ComponentName } from '@onesaz/ui'
All components are built with React forwardRef, ship full TypeScript types, and use Tailwind CSS with semantic CSS variables (--accent, --muted, --border, --foreground, --background, etc.).
- Accordion
- Alert
- AlertDialog
- Avatar
- Backdrop
- Badge
- BottomNavigation
- Box
- Breadcrumbs
- Button
- Card
- Charts
- Checkbox
- Chip
- Combobox
- DataList
- Dialog
- Drawer / Sheet
- DropdownMenu
- Form
- Grid
- Input
- InputAdornment
- Label
- List
- Pagination
- Popover
- Progress
- Radio
- RangeSlider
- Select
- Separator
- Sidebar
- Skeleton
- Slider
- Snackbar
- Spinner
- Stack
- Switch
- Table
- Tabs
- TextField
- Textarea
- Tooltip
- TopBar
- Typography
Animated accordion built on Radix UI. Supports single and multiple open items.
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@onesaz/ui'
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Section 1</AccordionTrigger>
<AccordionContent>Content for section 1</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Section 2</AccordionTrigger>
<AccordionContent>Content for section 2</AccordionContent>
</AccordionItem>
</Accordion>Exports: Accordion, AccordionItem, AccordionTrigger, AccordionContent
The AccordionTrigger includes an animated chevron that rotates when the item is open. Inherits all Radix UI Accordion props (type, defaultValue, value, onValueChange, collapsible, etc.).
Dismissible alert banners with icon, color variants, and optional close button.
import { Alert, AlertTitle, AlertDescription } from '@onesaz/ui'
// Basic alert
<Alert variant="success">
<AlertTitle>Success</AlertTitle>
<AlertDescription>Your changes were saved.</AlertDescription>
</Alert>
// With close button
<Alert variant="error" onClose={() => setOpen(false)}>
<AlertTitle>Error</AlertTitle>
<AlertDescription>Something went wrong.</AlertDescription>
</Alert>
// Hide default icon
<Alert variant="warning" icon={null}>
<AlertTitle>Warning</AlertTitle>
<AlertDescription>No icon here.</AlertDescription>
</Alert>Exports: Alert, AlertTitle, AlertDescription
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
`'default' | 'success' | 'warning' |
onClose |
() => void |
— | If provided, shows a close button |
icon |
`React.ReactNode | null` | — |
Modal dialog for destructive confirmation actions. Built on Radix UI.
import {
AlertDialog, AlertDialogTrigger, AlertDialogContent,
AlertDialogHeader, AlertDialogFooter,
AlertDialogTitle, AlertDialogDescription,
AlertDialogAction, AlertDialogCancel
} from '@onesaz/ui'
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Delete</Button>
</AlertDialogTrigger>
<AlertDialogContent variant="destructive" showIcon>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Delete</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>Exports: AlertDialog, AlertDialogTrigger, AlertDialogPortal, AlertDialogOverlay, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
`'default' | 'destructive' | 'success' |
showIcon |
boolean |
false |
Show a contextual icon |
User avatar with image, fallback text, sizes, shapes, and group stacking.
import { Avatar, AvatarGroup } from '@onesaz/ui'
// Single avatar
<Avatar src="/photo.jpg" alt="Jane Doe" size="md" />
// Fallback text when no image
<Avatar fallback="JD" size="lg" />
// Square shape
<Avatar src="/photo.jpg" alt="Jane" shape="square" size="sm" />
// Bordered
<Avatar src="/photo.jpg" alt="Jane" bordered />
// Group with overflow count
<AvatarGroup max={3} size="sm">
<Avatar src="/a.jpg" alt="A" />
<Avatar src="/b.jpg" alt="B" />
<Avatar src="/c.jpg" alt="C" />
<Avatar src="/d.jpg" alt="D" />
</AvatarGroup>Exports: Avatar, AvatarGroup
| Prop | Type | Default | Description |
|---|---|---|---|
src |
string |
— | Image source URL |
alt |
string |
— | Alt text for the image |
size |
`'xs' | 'sm' | 'md' |
fallback |
string |
— | Initials/text shown when image is absent |
shape |
`'circle' | 'square'` | 'circle' |
bordered |
boolean |
false |
Adds a ring border |
fallbackElement |
React.ReactNode |
— | Custom element for fallback |
| Prop | Type | Default | Description |
|---|---|---|---|
max |
number |
— | Maximum avatars before showing overflow count |
size |
Avatar['size'] |
'md' |
Size applied to all child avatars |
Full-screen overlay backdrop. Renders into a portal by default.
import { Backdrop } from '@onesaz/ui'
<Backdrop open={loading} />
<Backdrop open={open} invisible transitionDuration={300} />Exports: Backdrop
| Prop | Type | Default | Description |
|---|---|---|---|
open |
boolean |
— | Whether the backdrop is visible |
invisible |
boolean |
false |
Transparent backdrop (no dimming) |
transitionDuration |
number |
225 |
Fade transition duration in ms |
keepMounted |
boolean |
false |
Keep DOM node after close |
disablePortal |
boolean |
false |
Render inline instead of in portal |
disableScrollLock |
boolean |
false |
Do not lock body scroll when open |
Small status badge with color and variant options.
import { Badge } from '@onesaz/ui'
<Badge>Default</Badge>
<Badge color="success" variant="contained">Active</Badge>
<Badge color="error" variant="outlined">Error</Badge>
<Badge color="warning" variant="text">Pending</Badge>Exports: Badge
| Prop | Type | Default | Description |
|---|---|---|---|
color |
`'default' | 'success' | 'warning' |
variant |
`'contained' | 'outlined' | 'text'` |
Mobile-style bottom navigation bar.
import { BottomNavigation, BottomNavigationAction } from '@onesaz/ui'
import { HomeIcon, SearchIcon, UserIcon } from 'lucide-react'
const [value, setValue] = React.useState('home')
<BottomNavigation value={value} onChange={(val) => setValue(val)} showLabels>
<BottomNavigationAction label="Home" icon={<HomeIcon />} value="home" />
<BottomNavigationAction label="Search" icon={<SearchIcon />} value="search" />
<BottomNavigationAction label="Profile" icon={<UserIcon />} value="profile" />
</BottomNavigation>Exports: BottomNavigation, BottomNavigationAction
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string |
— | Currently active item value |
onChange |
(value: string) => void |
— | Callback when item is selected |
showLabels |
boolean |
false |
Always show labels (not just on active) |
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
— | Label text |
icon |
React.ReactNode |
— | Icon element |
value |
string |
— | Value used for selection |
showLabel |
boolean |
— | Override parent showLabels |
Low-level layout primitive with inline style props mapped to Tailwind classes.
import { Box } from '@onesaz/ui'
<Box display="flex" alignItems="center" gap={4} p={6} rounded="lg" bg="muted">
<Box as="span" color="primary">Icon</Box>
<Box flexDirection="column">Content</Box>
</Box>Exports: Box
| Prop | Type | Description |
|---|---|---|
as |
React.ElementType |
Render as a different element (default: div) |
display |
`'block' | 'flex' |
flexDirection |
`'row' | 'col' |
alignItems |
`'start' | 'center' |
justifyContent |
`'start' | 'center' |
flexWrap |
`'nowrap' | 'wrap' |
gap |
`0 | 1 |
p |
0–16 |
Padding (all sides) |
px |
0–16 |
Padding horizontal |
py |
0–16 |
Padding vertical |
m |
0–16 |
Margin (all sides) |
mx |
0–16 |
Margin horizontal |
my |
0–16 |
Margin vertical |
rounded |
`'none' | 'sm' |
shadow |
`'none' | 'sm' |
bg |
string |
Background color (Tailwind utility suffix) |
color |
string |
Text color (Tailwind utility suffix) |
border |
boolean |
Show border |
borderColor |
string |
Border color |
w |
string |
Width |
h |
string |
Height |
position |
`'static' | 'relative' |
overflow |
`'auto' | 'hidden' |
Breadcrumb navigation with collapse support.
import {
Breadcrumbs, BreadcrumbItem, BreadcrumbLink,
BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis
} from '@onesaz/ui'
<Breadcrumbs maxItems={4} itemsBeforeCollapse={1} itemsAfterCollapse={2}>
<BreadcrumbItem href="/">Home</BreadcrumbItem>
<BreadcrumbItem href="/products">Products</BreadcrumbItem>
<BreadcrumbItem href="/products/category">Category</BreadcrumbItem>
<BreadcrumbItem current>Current Page</BreadcrumbItem>
</Breadcrumbs>Exports: Breadcrumbs, BreadcrumbItem, BreadcrumbLink, BreadcrumbSeparator, BreadcrumbEllipsis, BreadcrumbPage
| Prop | Type | Default | Description |
|---|---|---|---|
separator |
React.ReactNode |
/ |
Custom separator element |
maxItems |
number |
— | Max breadcrumbs before collapsing |
itemsBeforeCollapse |
number |
1 |
Items to show before ellipsis |
itemsAfterCollapse |
number |
2 |
Items to show after ellipsis |
| Prop | Type | Description |
|---|---|---|
current |
boolean |
Marks as the current (active) page |
href |
string |
Link href |
onClick |
() => void |
Click handler |
Versatile button with variants, colors, sizes, loading state, icons, and group support.
import { Button, IconButton, ButtonGroup } from '@onesaz/ui'
import { PlusIcon, TrashIcon } from 'lucide-react'
// Basic variants
<Button>Default</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="destructive">Destructive</Button>
// Color override
<Button color="success">Save</Button>
<Button variant="outline" color="error">Delete</Button>
<Button variant="secondary" color="warning">Warning</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon"><PlusIcon /></Button>
// Icons
<Button startIcon={<PlusIcon />}>Add Item</Button>
<Button endIcon={<TrashIcon />}>Remove</Button>
// Loading
<Button loading>Saving...</Button>
// Full width
<Button fullWidth>Submit</Button>
// Icon button (circular, accessible)
<IconButton aria-label="Add item" size="md">
<PlusIcon />
</IconButton>
<IconButton aria-label="Delete" size="sm" rounded color="error">
<TrashIcon />
</IconButton>
// Button group
<ButtonGroup variant="outline" orientation="horizontal">
<Button>Left</Button>
<Button>Center</Button>
<Button>Right</Button>
</ButtonGroup>Exports: Button, IconButton, ButtonGroup
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
`'default' | 'destructive' | 'outline' |
size |
`'default' | 'sm' | 'lg' |
color |
`'default' | 'success' | 'warning' |
fullWidth |
boolean |
false |
Take full container width |
loading |
boolean |
false |
Show spinner and disable button |
startIcon |
React.ReactNode |
— | Icon before label |
endIcon |
React.ReactNode |
— | Icon after label |
disabled |
boolean |
— | Disable the button |
| Prop | Type | Default | Description |
|---|---|---|---|
size |
`'xs' | 'sm' | 'md' |
rounded |
boolean |
false |
Circular shape |
aria-label |
string |
required | Accessibility label |
variant |
same as Button | 'ghost' |
Visual variant |
color |
same as Button | 'default' |
Color override |
loading |
boolean |
false |
Show spinner |
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
Button variant | — | Applied to all child buttons |
size |
Button size | — | Applied to all child buttons |
color |
Button color | — | Applied to all child buttons |
orientation |
`'horizontal' | 'vertical'` | 'horizontal' |
disabled |
boolean |
— | Disable all child buttons |
fullWidth |
boolean |
false |
Stretch to fill container |
Content container with optional header, footer, title, and description.
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@onesaz/ui'
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here.</CardDescription>
</CardHeader>
<CardContent>
<p>Main content area</p>
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>Exports: Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent
All sub-components are standard div elements with className and ref support. No additional props beyond standard HTML div attributes.
Data visualization components built on Recharts. All charts use theme-aware colors.
import {
BarChart, LineChart, PieChart, AreaChart,
ScatterChart, RadarChart, DonutChart,
ProgressCard, ProgressDonut, MultiProgressDonut
} from '@onesaz/ui'// Simple bar chart
<BarChart
data={[{ name: 'Jan', value: 400 }, { name: 'Feb', value: 300 }]}
dataKey="value"
height={300}
showGrid
showTooltip
showLegend
/>
// Grouped bar chart
<BarChart
data={data}
dataKeys={['revenue', 'profit']}
colors={['#6366f1', '#22c55e']}
height={300}
/>| Prop | Type | Default | Description |
|---|---|---|---|
data |
object[] |
— | Chart data array |
dataKey |
string |
— | Single bar data key |
dataKeys |
string[] |
— | Multiple bars (grouped) |
fill |
string |
— | Bar fill color |
name |
string |
— | Series name for legend/tooltip |
width |
`number | string` | '100%' |
height |
number |
300 |
Chart height |
margin |
object |
— | Chart margins |
showGrid |
boolean |
false |
Show grid lines |
showTooltip |
boolean |
true |
Show tooltip on hover |
showLegend |
boolean |
false |
Show legend |
xAxis |
object |
— | X-axis configuration |
yAxis |
object |
— | Y-axis configuration |
barProps |
object |
— | Additional props passed to Bar |
labelList |
boolean |
false |
Show value labels on bars |
colors |
string[] |
— | Colors for multi-bar chart |
tooltip |
React.ReactNode |
— | Custom tooltip component |
className |
string |
— | Additional CSS classes |
<LineChart
data={[{ month: 'Jan', sales: 400 }, { month: 'Feb', sales: 300 }]}
dataKey="sales"
xDataKey="month"
height={300}
showGrid
showTooltip
smooth
/>Similar to BarChart with additional:
| Prop | Type | Default | Description |
|---|---|---|---|
dataKey |
string |
— | Single line data key |
dataKeys |
string[] |
— | Multiple lines |
xDataKey |
string |
'name' |
X-axis data key |
smooth |
boolean |
false |
Curved/smooth line |
dot |
boolean |
false |
Show dots on data points |
<AreaChart
data={data}
dataKey="value"
height={300}
showGrid
gradient
/>Same as LineChart with additional:
| Prop | Type | Default | Description |
|---|---|---|---|
gradient |
boolean |
true |
Fill area with gradient |
stackId |
string |
— | Stack areas with same stackId |
<PieChart
data={[
{ name: 'Group A', value: 400 },
{ name: 'Group B', value: 300 },
]}
height={300}
showTooltip
showLegend
/>| Prop | Type | Default | Description |
|---|---|---|---|
data |
Array<{ name: string; value: number }> |
— | Pie segments |
width |
`number | string` | '100%' |
height |
number |
300 |
Chart height |
innerRadius |
number |
0 |
Inner radius (>0 = donut) |
outerRadius |
number |
80 |
Outer radius |
showTooltip |
boolean |
true |
Show tooltip |
showLegend |
boolean |
false |
Show legend |
colors |
string[] |
— | Custom segment colors |
<DonutChart
data={[{ name: 'Used', value: 70 }, { name: 'Free', value: 30 }]}
height={300}
showTooltip
showLegend
advancedStyling={{ enableGradients: true, enableShadows: true }}
/>DonutChart is a PieChart with innerRadius > 0 and supports:
| Prop | Type | Description |
|---|---|---|
advancedStyling |
{ enableGradients?: boolean; enableShadows?: boolean } |
Gradient/shadow effects |
<ScatterChart data={data} height={300} />
<RadarChart data={data} dataKeys={['score']} height={300} />Compact card showing a question number and percentage with a mini donut chart.
<ProgressCard
questionNum={5}
percentage={72}
onClick={(num) => console.log(num)}
donutSize={60}
strokeWidth={4}
enableGradients
enableShadows
backgroundColor="#E0E4E8"
getColor={(pct) => pct <= 50 ? ['#22c55e', '#16a34a'] : ['#ef4444', '#dc2626']}
typography={{ questionFontSize: 'text-lg', questionColor: 'text-foreground', percentageFontSize: 'text-sm' }}
/>| Prop | Type | Default | Description |
|---|---|---|---|
questionNum |
number |
— | Question/item number displayed |
percentage |
number |
— | Percentage value (0–100) |
onClick |
(num: number) => void |
— | Click handler |
donutSize |
number |
— | Size of the donut SVG |
strokeWidth |
number |
— | Stroke width of the donut arc |
backgroundColor |
string |
'#E0E4E8' |
Background circle color |
getColor |
(pct: number) => [string, string] |
— | Returns [startColor, endColor] |
enableShadows |
boolean |
— | Enable shadow filter |
enableGradients |
boolean |
— | Enable gradient fill |
typography |
{ questionFontSize, questionColor, percentageFontSize } |
— | Typography overrides |
Single donut chart with multiple colored segments (one per data item).
<ProgressDonut
data={[
{ value: 75, label: 'Math' },
{ value: 45, label: 'Science' },
]}
width={300}
height={300}
innerRadius={60}
outerRadius={80}
showTooltip
showLegend
getColor={(value) => value <= 30 ? '#22c55e' : value <= 50 ? '#3b82f6' : '#ef4444'}
/>| Prop | Type | Default | Description |
|---|---|---|---|
data |
Array<{ value: number; label?: string }> |
[] |
Data segments |
width |
`number | string` | 300 |
height |
`number | string` | 300 |
innerRadius |
number |
60 |
Inner radius |
outerRadius |
number |
80 |
Outer radius |
showTooltip |
boolean |
true |
Show tooltip |
showLegend |
boolean |
false |
Show legend |
getColor |
(value: number) => string |
— | Custom color per segment |
Array of individual donut charts, one per data item, laid out in a flex row.
<MultiProgressDonut
data={[
{ value: 30, label: 'Q1' },
{ value: 55, label: 'Q2' },
{ value: 80, label: 'Q3' },
]}
size={80}
showPercentage
enableGradients
enableShadows
/>| Prop | Type | Default | Description |
|---|---|---|---|
data |
Array<{ value: number; label?: string }> |
[] |
Items to render |
size |
number |
80 |
Size of each donut SVG |
outerRadius |
number |
35 |
Outer radius of each donut |
strokeWidth |
number |
8 |
Progress arc stroke width |
backgroundColor |
string |
'#E0E4E8' |
Background circle color |
backgroundStrokeWidth |
number |
8 |
Background circle stroke width |
showPercentage |
boolean |
true |
Show percentage text in center |
getColor |
(value: number) => [string, string] |
— | Returns [startColor, endColor] |
enableShadows |
boolean |
true |
Enable shadow filters |
enableGradients |
boolean |
true |
Enable gradient fills |
Native HTML checkbox with indeterminate state support.
import { Checkbox } from '@onesaz/ui'
<Checkbox checked={checked} onChange={(e) => setChecked(e.target.checked)} />
<Checkbox indeterminate />
<Checkbox disabled />Exports: Checkbox
Extends all React.InputHTMLAttributes<HTMLInputElement> with:
| Prop | Type | Default | Description |
|---|---|---|---|
indeterminate |
boolean |
false |
Shows the indeterminate (dash) state |
Compact element representing an entity, attribute, or action.
import { Chip } from '@onesaz/ui'
import { StarIcon } from 'lucide-react'
// Basic
<Chip label="Active" />
<Chip label="Success" color="success" />
<Chip label="Error" color="error" variant="outlined" />
// With icon
<Chip label="Featured" icon={<StarIcon />} color="warning" />
// With avatar
<Chip label="Jane Doe" avatar={<img src="/avatar.jpg" alt="Jane" />} />
// Deletable
<Chip label="Removable" onDelete={() => console.log('deleted')} />
// Clickable
<Chip label="Clickable" clickable onClick={() => alert('clicked')} />
// Sizes
<Chip label="Small" size="small" />
<Chip label="Medium" size="medium" />
// Disabled
<Chip label="Disabled" disabled />
// As link
<Chip label="Link Chip" href="/path" />Exports: Chip
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
— | Text label (also accepts children) |
variant |
`'filled' | 'outlined'` | 'filled' |
color |
`'default' | 'success' | 'warning' |
size |
`'small' | 'medium'` | 'medium' |
icon |
React.ReactNode |
— | Icon before label (not shown if avatar present) |
avatar |
React.ReactNode |
— | Avatar element before label |
onDelete |
(event: React.SyntheticEvent) => void |
— | Shows delete button; called on click or Delete/Backspace key |
deleteIcon |
React.ReactNode |
— | Custom delete icon |
clickable |
boolean |
false |
Adds button role and cursor |
disabled |
boolean |
false |
Disables all interactions |
href |
string |
— | Renders as <a> link |
component |
React.ElementType |
— | Override root element |
Searchable select with single and multi-select modes. Supports virtualization for large option lists.
import { Combobox } from '@onesaz/ui'
// Single select
<Combobox
options={[
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
]}
value={value}
onChange={setValue}
placeholder="Select fruit..."
clearable
/>
// Multi select
<Combobox
multiple
options={options}
value={selectedValues}
onChange={setSelectedValues}
placeholder="Select items..."
selectAll
selectAllLabel="Select All"
maxDisplayItems={3}
/>
// Custom keys
<Combobox
options={users}
labelKey="name"
valueKey="id"
value={userId}
onChange={setUserId}
/>
// With adornments
<Combobox
options={options}
startAdornment={<SearchIcon />}
onStartAdornmentClick={() => {}}
value={value}
onChange={setValue}
/>
// Virtualized (for large lists)
<Combobox
options={largeList}
value={value}
onChange={setValue}
virtual
virtualItemHeight={36}
/>Exports: Combobox, ComboboxOption, ComboboxSingleProps, ComboboxMultipleProps, ComboboxProps
| Prop | Type | Default | Description |
|---|---|---|---|
options |
ComboboxOption[] |
— | Array of { label, value } objects (or custom keys) |
placeholder |
string |
— | Trigger placeholder text |
searchPlaceholder |
string |
— | Search input placeholder |
emptyMessage |
string |
— | Text shown when no options match |
disabled |
boolean |
false |
Disable the combobox |
clearable |
boolean |
false |
Show clear button |
openOnFocus |
boolean |
false |
Open dropdown on focus |
inputValue |
string |
— | Controlled search input value |
onInputChange |
(value: string) => void |
— | Search input change handler |
labelKey |
string |
'label' |
Key for option label |
valueKey |
string |
'value' |
Key for option value |
startAdornment |
React.ReactNode |
— | Element at start of trigger |
onStartAdornmentClick |
() => void |
— | Click handler for start adornment |
endAdornment |
React.ReactNode |
— | Element at end of trigger |
onEndAdornmentClick |
() => void |
— | Click handler for end adornment |
virtual |
boolean |
false |
Enable virtual scrolling |
virtualItemHeight |
number |
36 |
Height of each virtual item in px |
| Prop | Type | Description |
|---|---|---|
value |
`string | null` |
defaultValue |
string |
Uncontrolled default value |
onChange |
`(value: string | null) => void` |
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string[] |
— | Selected values array |
defaultValue |
string[] |
— | Uncontrolled default |
onChange |
(value: string[]) => void |
— | Change handler |
selectAll |
boolean |
false |
Show "Select All" option |
selectAllLabel |
string |
'Select All' |
Label for "Select All" option |
maxDisplayItems |
number |
— | Max chips shown in trigger before "+N" |
Structured key-value data display, horizontal or vertical.
Exports: DataList, DataListItem, DataListLabel, DataListValue
| Prop | Type | Default | Description |
|---|---|---|---|
orientation |
`'horizontal' | 'vertical'` | 'vertical' |
size |
`'1' | '2' | '3'` |
| Prop | Type | Default | Description |
|---|---|---|---|
align |
`'start' | 'center' | 'end' |
| Prop | Type | Default | Description |
|---|---|---|---|
width |
`string | number` | — |
minWidth |
`string | number` | — |
maxWidth |
`string | number` | — |
color |
`'default' | 'muted' | 'primary' |
highContrast |
boolean |
false |
High contrast text |
Modal dialog built on Radix UI.
import {
Dialog, DialogTrigger, DialogContent,
DialogHeader, DialogFooter,
DialogTitle, DialogDescription, DialogClose
} from '@onesaz/ui'
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent size="md">
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog description text.</DialogDescription>
</DialogHeader>
<p>Dialog body content goes here.</p>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Confirm</Button>
</DialogFooter>
</DialogContent>
</Dialog>Exports: Dialog, DialogTrigger, DialogPortal, DialogClose, DialogOverlay, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription
| Prop | Type | Default | Description |
|---|---|---|---|
size |
`'sm' | 'md' | 'lg' |
hideCloseButton |
boolean |
false |
Hide the default X close button |
Slide-out panel from any edge. Also exported as Sheet (same API, different name).
import {
Drawer, DrawerTrigger, DrawerContent,
DrawerHeader, DrawerTitle, DrawerDescription,
DrawerBody, DrawerFooter, DrawerClose
} from '@onesaz/ui'
<Drawer>
<DrawerTrigger asChild>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerContent side="right">
<DrawerHeader>
<DrawerTitle>Settings</DrawerTitle>
<DrawerDescription>Manage your preferences.</DrawerDescription>
</DrawerHeader>
<DrawerBody>
<p>Drawer content</p>
</DrawerBody>
<DrawerFooter>
<DrawerClose asChild>
<Button variant="outline">Close</Button>
</DrawerClose>
<Button>Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>Drawer Exports: Drawer, DrawerTrigger, DrawerClose, DrawerPortal, DrawerOverlay, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerBody, DrawerFooter
Sheet Exports (aliases): Sheet, SheetTrigger, SheetClose, SheetPortal, SheetOverlay, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter
| Prop | Type | Default | Description |
|---|---|---|---|
side |
`'left' | 'right' | 'top' |
showClose |
boolean |
true |
Show the X close button |
Context menu / dropdown built on Radix UI.
import {
DropdownMenu, DropdownMenuTrigger, DropdownMenuContent,
DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator,
DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem,
DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent,
DropdownMenuShortcut, DropdownMenuGroup
} from '@onesaz/ui'
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Options</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
Profile
<DropdownMenuShortcut>Cmd+P</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem checked={checked} onCheckedChange={setChecked}>
Show toolbar
</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
<DropdownMenuSub>
<DropdownMenuSubTrigger>More options</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem>Sub item</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
<DropdownMenuRadioItem value="light">Light</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="dark">Dark</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>Exports: DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuRadioGroup
| Component | Extra Prop | Type | Description |
|---|---|---|---|
DropdownMenuItem |
inset |
boolean |
Adds left padding for text alignment with icons |
DropdownMenuSubTrigger |
inset |
boolean |
Same as above |
DropdownMenuLabel |
inset |
boolean |
Same as above |
Form control primitives for building accessible forms.
import { FormControl, FormLabel, FormHelperText, FormGroup, useFormControl } from '@onesaz/ui'
// Vertical layout (default)
<FormControl error={hasError} required fullWidth>
<FormLabel>Email</FormLabel>
<Input type="email" />
<FormHelperText>{hasError ? 'Invalid email' : 'Enter your email'}</FormHelperText>
</FormControl>
// Horizontal layout
<FormControl orientation="horizontal" margin="normal">
<FormLabel>Active</FormLabel>
<Switch />
</FormControl>
// Grouping checkboxes
<FormGroup row>
<FormControl>
<Checkbox /> <FormLabel>Option A</FormLabel>
</FormControl>
<FormControl>
<Checkbox /> <FormLabel>Option B</FormLabel>
</FormControl>
</FormGroup>Exports: FormControl, FormLabel, FormHelperText, FormGroup, useFormControl
| Prop | Type | Default | Description |
|---|---|---|---|
error |
boolean |
— | Error state (propagated via context) |
disabled |
boolean |
— | Disabled state (propagated via context) |
required |
boolean |
— | Required state (propagated via context) |
fullWidth |
boolean |
false |
Full width layout |
margin |
`'none' | 'dense' | 'normal'` |
orientation |
`'vertical' | 'horizontal'` | 'vertical' |
| Prop | Type | Description |
|---|---|---|
error |
boolean |
Error state (auto-inherited from FormControl) |
disabled |
boolean |
Disabled state (auto-inherited) |
required |
boolean |
Required indicator (auto-inherited) |
| Prop | Type | Description |
|---|---|---|
error |
boolean |
Error state (auto-inherited from FormControl) |
disabled |
boolean |
Disabled state (auto-inherited) |
| Prop | Type | Default | Description |
|---|---|---|---|
row |
boolean |
false |
Horizontal (row) layout |
CSS Grid layout utility.
import { Grid } from '@onesaz/ui'
// Container
<Grid container spacing={4} columns={12}>
<Grid item xs={12} md={6} lg={4}>
<Card>...</Card>
</Grid>
<Grid item xs={12} md={6} lg={4}>
<Card>...</Card>
</Grid>
</Grid>Exports: Grid
| Prop | Type | Default | Description |
|---|---|---|---|
container |
boolean |
false |
Marks as grid container |
item |
boolean |
false |
Marks as grid item |
xs |
1–12 |
— | Columns on xs breakpoint |
sm |
1–12 |
— | Columns on sm breakpoint |
md |
1–12 |
— | Columns on md breakpoint |
lg |
1–12 |
— | Columns on lg breakpoint |
xl |
1–12 |
— | Columns on xl breakpoint |
xxl |
1–12 |
— | Columns on 2xl breakpoint |
spacing |
number |
— | Gap between items |
rowSpacing |
number |
— | Row gap |
columnSpacing |
number |
— | Column gap |
columns |
`1 | 2 | 3 |
alignItems |
string |
— | Align items |
justifyItems |
string |
— | Justify items |
justifyContent |
string |
— | Justify content |
Styled text input with adornment support.
import { Input } from '@onesaz/ui'
import { SearchIcon } from 'lucide-react'
<Input placeholder="Search..." />
<Input inputSize="sm" placeholder="Small input" />
<Input inputSize="lg" placeholder="Large input" />
<Input error placeholder="Error state" />
<Input
startAdornment={<SearchIcon className="h-4 w-4 text-muted-foreground" />}
placeholder="Search..."
/>
<Input
endAdornment={<span className="text-sm text-muted-foreground">USD</span>}
placeholder="Amount"
/>Exports: Input
Extends all React.InputHTMLAttributes<HTMLInputElement> with:
| Prop | Type | Default | Description |
|---|---|---|---|
inputSize |
`'sm' | 'md' | 'lg'` |
error |
boolean |
false |
Error state styling |
startAdornment |
React.ReactNode |
— | Element at the start |
endAdornment |
React.ReactNode |
— | Element at the end |
containerClassName |
string |
— | Class applied to the wrapper div |
Note: Use
inputSize(notsize) to control the input dimensions. The nativesizeHTML attribute still works for character width.
Decorative element for use inside an Input.
import { InputAdornment, Input } from '@onesaz/ui'
<Input
startAdornment={
<InputAdornment position="start">$</InputAdornment>
}
endAdornment={
<InputAdornment position="end" disablePointerEvents>
USD
</InputAdornment>
}
/>Exports: InputAdornment
| Prop | Type | Default | Description |
|---|---|---|---|
position |
`'start' | 'end'` | — |
disablePointerEvents |
boolean |
false |
Disable mouse events on adornment |
Accessible form label.
import { Label } from '@onesaz/ui'
<Label htmlFor="email">Email address</Label>
<input id="email" type="email" />Exports: Label
Standard HTML <label> element with styling. Accepts all React.LabelHTMLAttributes<HTMLLabelElement>.
Flexible list component with support for dense mode, dividers, selection, and leading/trailing content.
import { List, ListItem, ListItemButton } from '@onesaz/ui'
import { FolderIcon, ChevronRightIcon } from 'lucide-react'
// Basic list
<List>
<ListItem>Simple item</ListItem>
<ListItem>Another item</ListItem>
</List>
// With icons and actions
<List dividers dense>
<ListItem
leading={<FolderIcon className="h-5 w-5" />}
trailing={<ChevronRightIcon className="h-4 w-4" />}
clickable
onClick={() => navigate('/folder')}
>
Documents
</ListItem>
</List>
// Interactive list items
<List>
<ListItemButton selected onClick={handleClick} autoFocus>
Selected Item
</ListItemButton>
<ListItemButton onClick={handleClick}>
Normal Item
</ListItemButton>
</List>Exports: List, ListItem, ListItemButton
| Prop | Type | Default | Description |
|---|---|---|---|
dividers |
boolean |
false |
Show dividers between items |
dense |
boolean |
false |
Reduced padding |
clickable |
boolean |
false |
Apply hover styles to all items |
disablePadding |
boolean |
false |
Remove list padding |
| Prop | Type | Default | Description |
|---|---|---|---|
selected |
boolean |
false |
Highlight as selected |
disabled |
boolean |
false |
Disable interactions |
clickable |
boolean |
false |
Apply hover/cursor styles |
leading |
React.ReactNode |
— | Content at the start (icon, avatar) |
trailing |
React.ReactNode |
— | Content at the end (icon, badge) |
secondaryAction |
React.ReactNode |
— | Absolute-positioned action at end |
inset |
boolean |
false |
Indent to align with icon items |
disableGutters |
boolean |
false |
Remove horizontal padding |
alignItems |
`'start' | 'center'` | 'center' |
| Prop | Type | Default | Description |
|---|---|---|---|
selected |
boolean |
false |
Highlight as selected |
dense |
boolean |
false |
Reduced padding |
disableGutters |
boolean |
false |
Remove horizontal padding |
divider |
boolean |
false |
Add bottom border |
alignItems |
`'start' | 'center'` | 'center' |
autoFocus |
boolean |
false |
Auto-focus on mount |
Pagination controls with compound component pattern.
import {
Pagination, PaginationContent, PaginationItem,
PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis
} from '@onesaz/ui'
// Named exports
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>
// Compound namespace
<Pagination>
<Pagination.Content>
<Pagination.Item>
<Pagination.Previous href="#" />
</Pagination.Item>
</Pagination.Content>
</Pagination>Exports: Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis
PaginationLink accepts an isActive prop to apply active styling.
Floating content panel built on Radix UI.
import { Popover, PopoverTrigger, PopoverContent } from '@onesaz/ui'
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open Popover</Button>
</PopoverTrigger>
<PopoverContent>
<p>Popover content here.</p>
</PopoverContent>
</Popover>Exports: Popover, PopoverTrigger, PopoverContent, PopoverAnchor
PopoverContent accepts standard Radix popover content props (side, align, sideOffset, etc.).
Linear and circular progress indicators.
import { LinearProgress, CircularProgress, Progress } from '@onesaz/ui'
// Linear (Progress is an alias for LinearProgress)
<LinearProgress value={65} />
<Progress value={65} variant="success" size="lg" showValue />
<LinearProgress value={50} animated />
<LinearProgress value={30} formatValue={(v) => `${v} of 100`} showValue />
// Circular
<CircularProgress value={75} />
<CircularProgress value={60} variant="error" size="xl" showValue />
<CircularProgress value={40} size={120} thickness={6} />
<CircularProgress value={80}>
<span className="text-sm font-bold">80%</span>
</CircularProgress>Exports: LinearProgress, CircularProgress, Progress
| Prop | Type | Default | Description |
|---|---|---|---|
value |
number |
0 |
Progress value (0–100) |
variant |
`'default' | 'success' | 'warning' |
size |
`'sm' | 'md' | 'lg'` |
showValue |
boolean |
false |
Show percentage label |
formatValue |
(value: number) => string |
— | Custom value formatter |
animated |
boolean |
false |
Animated shimmer effect |
| Prop | Type | Default | Description |
|---|---|---|---|
value |
number |
0 |
Progress value (0–100) |
variant |
`'default' | 'success' | 'warning' |
size |
`'sm' | 'md' | 'lg' |
thickness |
number |
— | Stroke width |
showValue |
boolean |
false |
Show percentage in center |
formatValue |
(value: number) => string |
— | Custom value formatter |
children |
React.ReactNode |
— | Custom center content (overrides showValue) |
Radio group built on Radix UI.
import { RadioGroup, RadioGroupItem, Radio } from '@onesaz/ui'
// Primitive usage
<RadioGroup value={value} onValueChange={setValue} orientation="vertical">
<div className="flex items-center gap-2">
<RadioGroupItem value="option1" id="opt1" />
<label htmlFor="opt1">Option 1</label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="option2" id="opt2" />
<label htmlFor="opt2">Option 2</label>
</div>
</RadioGroup>
// Convenience Radio component
<RadioGroup value={value} onValueChange={setValue}>
<Radio value="a" label="Choice A" description="Description for A" />
<Radio value="b" label="Choice B" description="Description for B" />
</RadioGroup>
// Horizontal layout
<RadioGroup orientation="horizontal" size="lg">
<Radio value="yes" label="Yes" />
<Radio value="no" label="No" />
</RadioGroup>Exports: RadioGroup, RadioGroupItem, Radio
Extends Radix UI RadioGroup.Root props with:
| Prop | Type | Default | Description |
|---|---|---|---|
orientation |
`'horizontal' | 'vertical'` | 'vertical' |
size |
`'sm' | 'md' | 'lg'` |
Extends Radix UI RadioGroup.Item props with:
| Prop | Type | Description |
|---|---|---|
size |
`'sm' | 'md' |
| Prop | Type | Description |
|---|---|---|
value |
string |
Radio value |
label |
string |
Label text |
description |
string |
Helper description below label |
id |
string |
HTML id (auto-generated if omitted) |
Dual-handle range slider.
import { RangeSlider } from '@onesaz/ui'
<RangeSlider
value={[20, 80]}
onChange={(range) => setRange(range)}
showValues
valuePosition="top"
minLabel="Min"
maxLabel="Max"
valueFormatter={(v) => `$${v}`}
/>Exports: RangeSlider
| Prop | Type | Default | Description |
|---|---|---|---|
value |
[number, number] |
— | Controlled range value |
defaultValue |
[number, number] |
— | Uncontrolled default |
onChange |
(value: [number, number]) => void |
— | Change handler |
showValues |
boolean |
false |
Show value labels |
valuePosition |
`'top' | 'bottom'` | 'top' |
valueFormatter |
(v: number) => string |
— | Format the displayed value |
minLabel |
string |
— | Label at the minimum end |
maxLabel |
string |
— | Label at the maximum end |
Accessible select built on Radix UI with compound component pattern and a native fallback.
import {
Select, SelectTrigger, SelectValue, SelectContent,
SelectItem, SelectGroup, SelectLabel, SelectSeparator
} from '@onesaz/ui'
// Named exports
<Select>
<SelectTrigger>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Fruits</SelectLabel>
<SelectItem value="apple">Apple</SelectItem>
<SelectItem value="banana">Banana</SelectItem>
</SelectGroup>
<SelectSeparator />
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
// Compound namespace
<Select>
<Select.Trigger>
<Select.Value placeholder="Choose..." />
</Select.Trigger>
<Select.Content>
<Select.Item value="a">Option A</Select.Item>
</Select.Content>
</Select>Radix Select Exports: Select (also exposes .Trigger, .Value, .Content, .Item, .Group, .Label, .Separator, .ScrollUpButton, .ScrollDownButton on the namespace), SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton
import { NativeSelect, NativeSelectOption } from '@onesaz/ui'
<NativeSelect value={value} onChange={(e) => setValue(e.target.value)}>
<NativeSelectOption value="">Choose...</NativeSelectOption>
<NativeSelectOption value="a">Option A</NativeSelectOption>
<NativeSelectOption value="b">Option B</NativeSelectOption>
</NativeSelect>Exports: NativeSelect, NativeSelectOption
Visual divider line.
import { Separator } from '@onesaz/ui'
<Separator />
<Separator orientation="vertical" />Exports: Separator
| Prop | Type | Default | Description |
|---|---|---|---|
orientation |
`'horizontal' | 'vertical'` | 'horizontal' |
Collapsible sidebar navigation with context-aware sub-components.
import {
Sidebar, SidebarHeader, SidebarContent, SidebarFooter,
SidebarGroup, SidebarItem, SidebarSubMenu
} from '@onesaz/ui'
import { HomeIcon, SettingsIcon, FolderIcon } from 'lucide-react'
<Sidebar collapsed={collapsed} onCollapsedChange={setCollapsed} width={256} collapsedWidth={64}>
<SidebarHeader>
{!collapsed && <span className="font-bold">My App</span>}
</SidebarHeader>
<SidebarContent>
<SidebarGroup label="Navigation">
<SidebarItem icon={<HomeIcon />} active href="/">
Home
</SidebarItem>
<SidebarSubMenu icon={<FolderIcon />} label="Projects" defaultOpen>
<SidebarItem href="/projects/a">Project A</SidebarItem>
<SidebarItem href="/projects/b">Project B</SidebarItem>
</SidebarSubMenu>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarItem icon={<SettingsIcon />} href="/settings">
Settings
</SidebarItem>
</SidebarFooter>
</Sidebar>Exports: Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarGroup, SidebarItem, SidebarSubMenu
| Prop | Type | Default | Description |
|---|---|---|---|
collapsed |
boolean |
— | Controlled collapsed state |
onCollapsedChange |
(collapsed: boolean) => void |
— | Callback when state changes |
defaultCollapsed |
boolean |
false |
Uncontrolled default state |
width |
`number | string` | 256 |
collapsedWidth |
`number | string` | 64 |
bordered |
boolean |
true |
Show right border |
| Prop | Type | Description |
|---|---|---|
label |
string |
Section label (hidden when collapsed) |
| Prop | Type | Default | Description |
|---|---|---|---|
icon |
React.ReactNode |
— | Icon element |
active |
boolean |
false |
Active/selected state |
disabled |
boolean |
false |
Disabled state |
badge |
React.ReactNode |
— | Badge or count element (hidden when collapsed) |
href |
string |
— | Renders as <a> link |
onClick |
() => void |
— | Click handler |
| Prop | Type | Default | Description |
|---|---|---|---|
icon |
React.ReactNode |
— | Icon element |
label |
string |
required | Submenu trigger label |
defaultOpen |
boolean |
false |
Initially expanded |
Loading placeholder shapes.
import { Skeleton, SkeletonText, SkeletonAvatar, SkeletonCard, SkeletonTableRow } from '@onesaz/ui'
// Basic shapes
<Skeleton variant="text" width={200} />
<Skeleton variant="circular" width={40} height={40} />
<Skeleton variant="rectangular" width="100%" height={200} />
<Skeleton variant="rounded" width="100%" height={100} animation="wave" />
// Preset skeletons
<SkeletonText lines={3} />
<SkeletonAvatar size="md" />
<SkeletonCard />
<SkeletonTableRow columns={5} />Exports: Skeleton, SkeletonText, SkeletonAvatar, SkeletonCard, SkeletonTableRow
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
`'text' | 'circular' | 'rectangular' |
width |
`number | string` | — |
height |
`number | string` | — |
animation |
`'pulse' | 'wave' | 'none'` |
Single-handle range slider built on Radix UI.
import { Slider } from '@onesaz/ui'
<Slider
value={50}
onChange={(value) => setValue(value)}
showValue
valuePosition="top"
valueFormatter={(v) => `${v}%`}
/>Exports: Slider
| Prop | Type | Default | Description |
|---|---|---|---|
value |
number |
— | Controlled value |
defaultValue |
number |
— | Uncontrolled default |
onChange |
(value: number) => void |
— | Change handler |
showValue |
boolean |
false |
Show value label |
valuePosition |
`'top' | 'bottom' | 'left' |
valueFormatter |
(v: number) => string |
— | Format the displayed value |
Temporary notification messages with auto-dismiss and positioning.
import { Snackbar, SnackbarContent } from '@onesaz/ui'
// Simple
<Snackbar
open={open}
message="Changes saved successfully"
autoHideDuration={4000}
onClose={(reason) => setOpen(false)}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
/>
// With action button
<Snackbar
open={open}
onClose={() => setOpen(false)}
autoHideDuration={6000}
>
<SnackbarContent
message="Item deleted"
action={<Button size="sm" variant="ghost" onClick={handleUndo}>Undo</Button>}
/>
</Snackbar>
// Disable auto-hide
<Snackbar open={open} message="Persistent message" autoHideDuration={null} />Exports: Snackbar, SnackbarContent
| Prop | Type | Default | Description |
|---|---|---|---|
open |
boolean |
required | Whether the snackbar is visible |
message |
string |
— | Message text (shorthand) |
action |
React.ReactNode |
— | Action element (shorthand) |
autoHideDuration |
`number | null` | 6000 |
onClose |
`(reason: 'timeout' | 'clickaway' | 'escapeKeyDown') => void` |
anchorOrigin |
`{ vertical: 'top' | 'bottom'; horizontal: 'left' | 'center' |
transitionDuration |
number |
— | Fade transition duration ms |
disableWindowBlurListener |
boolean |
false |
Don't reset timer on window blur |
disablePortal |
boolean |
false |
Render inline (not in portal) |
children |
React.ReactNode |
— | Custom content (overrides message/action) |
| Prop | Type | Description |
|---|---|---|
message |
string |
Message text |
action |
React.ReactNode |
Action button/element |
Loading spinner indicator.
import { Spinner } from '@onesaz/ui'
<Spinner />
<Spinner size="sm" />
<Spinner size="lg" />Exports: Spinner
| Prop | Type | Default | Description |
|---|---|---|---|
size |
`'sm' | 'default' | 'lg'` |
Flex layout helper with direction, spacing, and divider support.
import { Stack, HStack, VStack } from '@onesaz/ui'
// Default: column direction
<Stack spacing={4}>
<div>Item 1</div>
<div>Item 2</div>
</Stack>
// Horizontal stack (HStack = Stack with direction="row")
<HStack spacing={2} align="center">
<Avatar src="/avatar.jpg" />
<span>Username</span>
</HStack>
// Vertical stack (VStack = Stack with direction="column")
<VStack spacing={3} justify="center">
<Button>Primary</Button>
<Button variant="outline">Secondary</Button>
</VStack>
// With dividers
<Stack spacing={2} divider={<Separator />} direction="column">
<div>Section 1</div>
<div>Section 2</div>
</Stack>Exports: Stack, HStack, VStack
| Prop | Type | Default | Description |
|---|---|---|---|
direction |
`'row' | 'column' | 'row-reverse' |
spacing |
`0 | 1 | 2 |
align |
string |
— | align-items value |
justify |
string |
— | justify-content value |
wrap |
string |
— | flex-wrap value |
divider |
React.ReactNode |
— | Divider element between children |
as |
React.ElementType |
'div' |
Render as different element |
HStack=Stackwithdirection="row".VStack=Stackwithdirection="column". The baseStackdefault direction is'column'.
Toggle switch control.
import { Switch } from '@onesaz/ui'
<Switch checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />
<Switch defaultChecked />
<Switch disabled />Exports: Switch
Extends React.InputHTMLAttributes<HTMLInputElement>. Key props: checked, defaultChecked, onChange, disabled.
Semantic HTML table with styling.
import {
Table, TableHeader, TableBody, TableFooter,
TableRow, TableHead, TableCell, TableCaption
} from '@onesaz/ui'
<Table>
<TableCaption>Monthly sales report</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Month</TableHead>
<TableHead>Revenue</TableHead>
<TableHead>Growth</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>January</TableCell>
<TableCell>$12,000</TableCell>
<TableCell>+5%</TableCell>
</TableRow>
<TableRow>
<TableCell>February</TableCell>
<TableCell>$14,500</TableCell>
<TableCell>+21%</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={2}>Total</TableCell>
<TableCell>$26,500</TableCell>
</TableRow>
</TableFooter>
</Table>Exports: Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption
All are semantic HTML elements with className and ref support. No additional custom props.
Tab panels with three visual variants: pill (default), underline, and vertical.
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@onesaz/ui'
<Tabs defaultValue="tab1">
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
<TabsTrigger value="tab3" disabled>Disabled</TabsTrigger>
</TabsList>
<TabsContent value="tab1">Content for Tab 1</TabsContent>
<TabsContent value="tab2">Content for Tab 2</TabsContent>
</Tabs>import {
Tabs, UnderlineTabsList, UnderlineTabsTrigger, UnderlineTabsContent
} from '@onesaz/ui'
<Tabs defaultValue="overview">
<UnderlineTabsList>
<UnderlineTabsTrigger value="overview">Overview</UnderlineTabsTrigger>
<UnderlineTabsTrigger value="issues" count={12}>Issues</UnderlineTabsTrigger>
<UnderlineTabsTrigger value="prs" count={3}>Pull Requests</UnderlineTabsTrigger>
</UnderlineTabsList>
<UnderlineTabsContent value="overview">Overview content</UnderlineTabsContent>
<UnderlineTabsContent value="issues">Issues list</UnderlineTabsContent>
</Tabs>UnderlineTabsTrigger accepts a count?: number prop to show a count badge.
import {
VerticalTabs, VerticalTabsList, VerticalTabsTrigger,
VerticalTabsContent, VerticalTabsGroupLabel
} from '@onesaz/ui'
import { UserIcon, LockIcon } from 'lucide-react'
<VerticalTabs defaultValue="profile">
<VerticalTabsList>
<VerticalTabsGroupLabel>Account</VerticalTabsGroupLabel>
<VerticalTabsTrigger value="profile" icon={<UserIcon />}>Profile</VerticalTabsTrigger>
<VerticalTabsTrigger value="security" icon={<LockIcon />}>Security</VerticalTabsTrigger>
</VerticalTabsList>
<VerticalTabsContent value="profile">Profile settings</VerticalTabsContent>
<VerticalTabsContent value="security">Security settings</VerticalTabsContent>
</VerticalTabs>VerticalTabsTrigger accepts an icon?: React.ReactNode prop. VerticalTabsGroupLabel is a non-interactive section header.
Exports: Tabs, TabsList, TabsTrigger, TabsContent, UnderlineTabsList, UnderlineTabsTrigger, UnderlineTabsContent, VerticalTabs, VerticalTabsList, VerticalTabsTrigger, VerticalTabsContent, VerticalTabsGroupLabel
Full-featured form input combining label, input, and helper text.
import { TextField } from '@onesaz/ui'
import { SearchIcon } from 'lucide-react'
<TextField label="Email" type="email" placeholder="you@example.com" />
<TextField label="Username" required helperText="Must be 3–20 characters" />
<TextField
label="Password"
type="password"
errorMessage="Password is required"
/>
<TextField label="Search" startAdornment={<SearchIcon className="h-4 w-4" />} />
<TextField label="Amount" endAdornment="USD" size="lg" fullWidth />Exports: TextField
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
— | Field label |
helperText |
string |
— | Helper text below input |
errorMessage |
string |
— | Error message (replaces helperText, sets error state) |
required |
boolean |
false |
Required indicator |
size |
`'sm' | 'md' | 'lg' |
fullWidth |
boolean |
false |
Take full container width |
startAdornment |
React.ReactNode |
— | Element at input start |
endAdornment |
React.ReactNode |
— | Element at input end |
inputProps |
React.InputHTMLAttributes<HTMLInputElement> |
— | Props forwarded to <input> |
InputProps |
object |
— | MUI-compatible input props |
InputLabelProps |
object |
— | Props for the label element |
inputRef |
React.Ref<HTMLInputElement> |
— | Ref for the input element |
Multi-line text input.
import { Textarea } from '@onesaz/ui'
<Textarea placeholder="Write your message..." rows={4} />
<Textarea disabled value="Read-only content" />Exports: Textarea
Extends all React.TextareaHTMLAttributes<HTMLTextAreaElement>. No additional custom props.
Floating label on hover/focus. Built on Radix UI.
import { Tooltip, TooltipProvider } from '@onesaz/ui'
// Wrap app with provider (once at root)
<TooltipProvider>
<App />
</TooltipProvider>
// Simple tooltip
<Tooltip content="Save your changes">
<Button>Save</Button>
</Tooltip>
// With options
<Tooltip
content="Delete permanently"
side="bottom"
align="center"
delayDuration={500}
showArrow
>
<Button variant="destructive">Delete</Button>
</Tooltip>
// Controlled
<Tooltip content="Hello" open={open} onOpenChange={setOpen}>
<Button>Hover me</Button>
</Tooltip>
// Disabled
<Tooltip content="Won't show" disabled>
<Button>No tooltip</Button>
</Tooltip>
// Primitive usage
import {
TooltipRoot, TooltipTrigger, TooltipContent, TooltipPortal, TooltipArrow
} from '@onesaz/ui'
<TooltipRoot>
<TooltipTrigger asChild>
<Button>Custom</Button>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="top" showArrow>
Custom tooltip
</TooltipContent>
</TooltipPortal>
</TooltipRoot>Exports: Tooltip, TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent, TooltipPortal, TooltipArrow
| Prop | Type | Default | Description |
|---|---|---|---|
content |
React.ReactNode |
— | Tooltip text/content |
side |
`'top' | 'right' | 'bottom' |
align |
`'start' | 'center' | 'end'` |
delayDuration |
number |
200 |
Open delay in ms |
open |
boolean |
— | Controlled open state |
onOpenChange |
(open: boolean) => void |
— | Open state change callback |
disabled |
boolean |
false |
Disable the tooltip |
showArrow |
boolean |
false |
Show arrow pointing to trigger |
className |
string |
— | Class for tooltip content |
| Prop | Type | Default | Description |
|---|---|---|---|
showArrow |
boolean |
false |
Show arrow |
Horizontal application header bar.
import {
TopBar, TopBarBrand, TopBarNav, TopBarNavItem,
TopBarSection, TopBarDivider
} from '@onesaz/ui'
<TopBar sticky bordered size="md">
<TopBarSection align="left">
<TopBarBrand logo={<Logo />} name="My App" href="/" />
<TopBarDivider />
<TopBarNav>
<TopBarNavItem href="/dashboard" active>Dashboard</TopBarNavItem>
<TopBarNavItem href="/reports">Reports</TopBarNavItem>
</TopBarNav>
</TopBarSection>
<TopBarSection align="right">
<IconButton aria-label="Notifications">
<BellIcon />
</IconButton>
<Avatar fallback="JD" size="sm" />
</TopBarSection>
</TopBar>Exports: TopBar, TopBarBrand, TopBarNav, TopBarNavItem, TopBarSection, TopBarDivider
| Prop | Type | Default | Description |
|---|---|---|---|
bordered |
boolean |
true |
Bottom border |
sticky |
boolean |
false |
Sticky positioned at top |
size |
`'sm' | 'md' | 'lg'` |
| Prop | Type | Description |
|---|---|---|
logo |
React.ReactNode |
Logo element |
name |
string |
Brand name text |
href |
string |
Link href wrapping the brand |
| Prop | Type | Default | Description |
|---|---|---|---|
align |
`'left' | 'center' | 'right'` |
| Prop | Type | Description |
|---|---|---|
active |
boolean |
Highlight as active |
Text rendering with semantic variants, colors, weights, alignment, and gradient support.
import { Typography, H1, H2, H3, H4, H5, H6, Text, Caption } from '@onesaz/ui'
// Using Typography component
<Typography variant="h1">Page Title</Typography>
<Typography variant="body1" color="secondary">Body text</Typography>
<Typography variant="caption" color="muted">Caption text</Typography>
<Typography variant="overline">Section Label</Typography>
// Colors
<Typography variant="h3" color="success">All good!</Typography>
<Typography variant="body2" color="error">Something failed</Typography>
<Typography variant="body1" color="warning">Be careful</Typography>
// Font weight
<Typography variant="body1" fontWeight="bold">Bold text</Typography>
<Typography variant="body1" fontWeight="light">Light text</Typography>
// Alignment
<Typography variant="body1" align="center">Centered</Typography>
// Text gradient
<Typography variant="h2" textGradient gradientColor="primary">
Gradient Heading
</Typography>
// Convenience shorthands
<H1>Heading 1</H1>
<H2>Heading 2</H2>
<H3>Heading 3</H3>
<H4>Heading 4</H4>
<H5>Heading 5</H5>
<H6>Heading 6</H6>
<Text>Body paragraph text</Text>
<Caption>Small caption text</Caption>
// Render as different element
<Typography variant="h1" as="p">Looks like h1, renders as p</Typography>
// No wrap
<Typography noWrap className="max-w-xs">
This text will be truncated with ellipsis
</Typography>Exports: Typography, H1, H2, H3, H4, H5, H6, Text, Caption
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
`'h1' | 'h2' | 'h3' |
color |
`'inherit' | 'primary' | 'secondary' |
fontWeight |
`'light' | 'regular' | 'medium' |
textTransform |
`'none' | 'uppercase' | 'lowercase' |
align |
`'left' | 'center' | 'right' |
verticalAlign |
`'top' | 'middle' | 'bottom' |
textGradient |
boolean |
false |
Enable gradient text effect |
gradientColor |
`'primary' | 'secondary' | 'info' |
opacity |
number |
— | CSS opacity (0–1) |
as |
React.ElementType |
— | Override rendered HTML element |
gutterBottom |
boolean |
false |
Add mb-2 bottom margin |
noWrap |
boolean |
false |
Truncate with ellipsis |
paragraph |
boolean |
false |
Add mb-4 bottom margin |
| Variant | Default Element |
|---|---|
h1–h6 |
<h1>–<h6> |
subtitle1, subtitle2 |
<h6> |
body1, body2 |
<p> |
caption, overline, inherit |
<span> |
| Component | Equivalent |
|---|---|
H1–H6 |
<Typography variant="h1"> through <Typography variant="h6"> |
Text |
<Typography variant="body1"> |
Caption |
<Typography variant="caption"> |