Skip to main content

Primitive Components

@thyris/ui exports application-independent controls and structural primitives. Choose the smallest component that preserves the required semantics and interaction behavior.

Actions​

ComponentMain ExportsUse It For
ButtonButton, buttonVariantsPrimary, secondary, destructive, ghost, link, and icon actions.
ToggleToggle, toggleVariantsOne independently pressed or unpressed control.
Toggle GroupToggleGroup, ToggleGroupItemA 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​

ComponentMain ExportsUse It For
InputInputSingle-line text, numeric, date, and native input values.
TextareaTextareaMulti-line free-form text.
LabelLabelA visible and clickable control name.
CheckboxCheckboxIndependent boolean values and zero-or-more selection.
Radio GroupRadioGroup, RadioGroupItemExactly one visible option.
SelectSelect, SelectTrigger, SelectValue, SelectContent, SelectItem and grouping partsOne option from a compact list.
SwitchSwitchA setting applied immediately.
FieldField, FieldGroup, FieldLabel, FieldDescription, FieldSeparatorStandard label, help text, grouping, and visual separation.
FormForm, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage, useFormFieldReact Hook Form state with accessible field associations.
URL List InputUrlListInputControlled 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​

ComponentMain ExportsUse It For
AlertAlert, AlertTitle, AlertDescriptionContextual informational or destructive feedback.
BadgeBadge, badgeVariantsCompact status, category, or metadata labels.
AvatarAvatar, AvatarImage, AvatarFallbackPerson or entity identity with fallback content.
ProgressProgressDeterminate task or quota completion.
TooltipTooltipProvider, Tooltip, TooltipTrigger, TooltipContentSupplementary 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​

ComponentMain ExportsUse It For
CardCard, CardHeader, CardTitle, CardDescription, CardContent, CardFooterOne bounded subject with related content and actions.
TableTable, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaptionSemantic tabular data with safe horizontal overflow.
ChartChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartLegendItem, useChartToken-aware Recharts composition.
Scroll AreaScrollArea, ScrollBarA deliberately bounded scrolling region.
SeparatorSeparatorMeaningful 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​

ComponentMain ExportsUse It For
DialogDialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogCloseA focused modal task or decision.
Responsive DialogResponsiveDialogContent, ResponsiveDialogHeader, ResponsiveDialogBody, ResponsiveDialogFooterLong or viewport-sensitive modal tasks.
Dropdown MenuRoot, trigger, content, items, groups, labels, separators, checkbox/radio items, and submenu partsCompact contextual commands or choices.
PopoverPopover, PopoverTrigger, PopoverContentLightweight anchored interactive content.
CollapsibleCollapsible, CollapsibleTrigger, CollapsibleContentOptional 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.

ComponentMain ExportsUse It For
BreadcrumbBreadcrumb, list, item, link, current page, separator, and ellipsis partsThe current page's real hierarchy.
TabsTabs, TabsList, TabsTrigger, TabsContentPeer sections within one context.
StepsSteps, StepsList, Step, StepIndicator, StepContent, StepMeta, StepLabelProgress through a short ordered workflow.
SidebarProvider, shell, inset, trigger, regions, groups, menu parts, input, rail, and useSidebarResponsive 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.

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​

RequirementChoose
Independent yes/no included in form submissionCheckbox
Setting applied as soon as it changesSwitch
Exactly one choice and all options should remain visibleRadio Group
Exactly one choice from a moderate compact listSelect
One pressed state such as pin or favoriteToggle
Related formatting or view modesToggle Group
Passive status labelBadge or StatusBadge pattern
Contextual commandsDropdown Menu
Focused confirmationDialog