Primitive Components
@thyris/ui exports application-independent controls and structural primitives. Choose the smallest component that preserves the required semantics and interaction behavior.
Actions
| Component | Main Exports | Use It For |
|---|---|---|
| Button | Button, buttonVariants | Primary, secondary, destructive, ghost, link, and icon actions. |
| Toggle | Toggle, toggleVariants | One independently pressed or unpressed control. |
| Toggle Group | ToggleGroup, ToggleGroupItem | A related single-select or multi-select action set. |
Button supports variant="default" | "destructive" | "outline" | "secondary" | "ghost" | "link", size="default" | "sm" | "lg" | "icon", and asChild.
import {Button} from "@thyris/ui"
import {Plus} from "lucide-react"
export function Actions() {
return (
<div className="flex flex-wrap gap-2">
<Button type="button">Save</Button>
<Button type="button" variant="outline">Cancel</Button>
<Button type="button" variant="destructive">Delete</Button>
<Button type="button" size="icon" aria-label="Add item">
<Plus aria-hidden="true" />
</Button>
</div>
)
}
Set type="button" for non-submit controls inside forms. Icon-only actions require an accessible name.
Form Controls
| Component | Main Exports | Use It For |
|---|---|---|
| Input | Input | Single-line text, numeric, date, and native input values. |
| Textarea | Textarea | Multi-line free-form text. |
| Label | Label | A visible and clickable control name. |
| Checkbox | Checkbox | Independent boolean values and zero-or-more selection. |
| Radio Group | RadioGroup, RadioGroupItem | Exactly one visible option. |
| Select | Select, SelectTrigger, SelectValue, SelectContent, SelectItem and grouping parts | One option from a compact list. |
| Switch | Switch | A setting applied immediately. |
| Field | Field, FieldGroup, FieldLabel, FieldDescription, FieldSeparator | Standard label, help text, grouping, and visual separation. |
| Form | Form, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage, useFormField | React Hook Form state with accessible field associations. |
| URL List Input | UrlListInput | Controlled entry and removal of multiple URL values. |
Every control needs a persistent label. Placeholders are examples, not labels. Use native input types and autocomplete metadata whenever possible.
Basic Field
import {Field, FieldDescription, FieldLabel, Input} from "@thyris/ui"
export function EmailField() {
return (
<Field>
<FieldLabel htmlFor="email">Email address</FieldLabel>
<Input id="email" name="email" type="email" autoComplete="email" />
<FieldDescription>Used for operational notifications.</FieldDescription>
</Field>
)
}
Selection Control
import {Label, Switch} from "@thyris/ui"
export function AuditSetting() {
return (
<div className="flex items-center justify-between gap-4">
<Label htmlFor="audit-events">Record audit events</Label>
<Switch id="audit-events" name="auditEvents" />
</div>
)
}
Feedback and Status
| Component | Main Exports | Use It For |
|---|---|---|
| Alert | Alert, AlertTitle, AlertDescription | Contextual informational or destructive feedback. |
| Badge | Badge, badgeVariants | Compact status, category, or metadata labels. |
| Avatar | Avatar, AvatarImage, AvatarFallback | Person or entity identity with fallback content. |
| Progress | Progress | Determinate task or quota completion. |
| Tooltip | TooltipProvider, Tooltip, TooltipTrigger, TooltipContent | Supplementary explanation for a named trigger. |
Status must remain understandable without color. Tooltips cannot contain critical instructions or be the only way to identify an icon-only action.
import {Alert, AlertDescription, AlertTitle, Badge} from "@thyris/ui"
export function SyncState() {
return (
<Alert>
<AlertTitle className="flex items-center gap-2">
Catalog sync <Badge variant="secondary">Running</Badge>
</AlertTitle>
<AlertDescription>
Product updates are being processed in the background.
</AlertDescription>
</Alert>
)
}
Data Display
| Component | Main Exports | Use It For |
|---|---|---|
| Card | Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter | One bounded subject with related content and actions. |
| Table | Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption | Semantic tabular data with safe horizontal overflow. |
| Chart | ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartLegendItem, useChart | Token-aware Recharts composition. |
| Scroll Area | ScrollArea, ScrollBar | A deliberately bounded scrolling region. |
| Separator | Separator | Meaningful visual or semantic division between groups. |
Tables require real headers and a caption or nearby heading. Essential chart values need a textual summary or table in addition to the visual.
Overlays and Disclosure
| Component | Main Exports | Use It For |
|---|---|---|
| Dialog | Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose | A focused modal task or decision. |
| Responsive Dialog | ResponsiveDialogContent, ResponsiveDialogHeader, ResponsiveDialogBody, ResponsiveDialogFooter | Long or viewport-sensitive modal tasks. |
| Dropdown Menu | Root, trigger, content, items, groups, labels, separators, checkbox/radio items, and submenu parts | Compact contextual commands or choices. |
| Popover | Popover, PopoverTrigger, PopoverContent | Lightweight anchored interactive content. |
| Collapsible | Collapsible, CollapsibleTrigger, CollapsibleContent | Optional secondary content revealed inline. |
Every dialog requires a title. Use a dialog for focused tasks, a popover for lightweight anchored controls, and a dropdown for contextual commands. Do not nest dialogs.
Navigation and Progress
| Component | Main Exports | Use It For |
|---|---|---|
| Breadcrumb | Breadcrumb, list, item, link, current page, separator, and ellipsis parts | The current page's real hierarchy. |
| Tabs | Tabs, TabsList, TabsTrigger, TabsContent | Peer sections within one context. |
| Steps | Steps, StepsList, Step, StepIndicator, StepContent, StepMeta, StepLabel | Progress through a short ordered workflow. |
| Sidebar | Provider, shell, inset, trigger, regions, groups, menu parts, input, rail, and useSidebar | Responsive application navigation structure. |
Breadcrumbs contain one current page. Tabs are not a replacement for unrelated routes or wizard steps. The application supplies sidebar routes, permissions, active state, and navigation behavior.
Sidebar Composition
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@thyris/ui"
export function ProductShell({children}: {children: React.ReactNode}) {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Workspace</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild isActive>
<a href="/overview">Overview</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header className="p-4"><SidebarTrigger /></header>
<main className="p-4">{children}</main>
</SidebarInset>
</SidebarProvider>
)
}
The consuming application should replace the plain anchor with its router link component while preserving the semantic link element.
Choosing Similar Controls
| Requirement | Choose |
|---|---|
| Independent yes/no included in form submission | Checkbox |
| Setting applied as soon as it changes | Switch |
| Exactly one choice and all options should remain visible | Radio Group |
| Exactly one choice from a moderate compact list | Select |
| One pressed state such as pin or favorite | Toggle |
| Related formatting or view modes | Toggle Group |
| Passive status label | Badge or StatusBadge pattern |
| Contextual commands | Dropdown Menu |
| Focused confirmation | Dialog |