Components
All components live in packages/ui/src/components/ and are consumed via the workspace alias @repo/ui/components/[name]. Each follows the CVA + Radix UI + Tailwind pattern and accepts a className prop for overrides.
The component library uses Tailwind CSS v4. Class names reference design tokens via
@theme inline. All color classes likebg-brand,text-foreground-muted, andborder-border-controlresolve to the token values defined in@repo/ui/theme.css.
Atom components
Button
Import: @repo/ui/components/button
The primary action component. Variants map to semantic intent. All variants share the same size scale and focus ring.
| Variant | Use case |
|---|---|
default / primary | Primary CTAs, form submits, strong positive actions |
secondary | Less prominent actions, paired with a primary button |
outline | Tertiary actions, cancel buttons |
ghost | Icon buttons, contextual actions in dense UI |
destructive | Delete, remove, irreversible actions |
warning | Actions with side effects, non-destructive but caution-warranting |
link | In-text navigation, lowest priority actions |
Size scale
Three sizes: sm (28px), md (32px, default), lg (40px). Each has a matching icon-only variant.
| Size | Height | Usage |
|---|---|---|
sm | 28px (h-7) | Filter bars, toggle pills, inline controls. Used in filter rows and toolbars (type filters, sort modes, sprint toggles). |
md (default) | 32px (h-8) | Action bar buttons, form actions, dialogs. The standard size for page-level actions like "New Task", "View PRD", split buttons. |
lg | 40px (h-10) | Hero CTAs, landing page buttons. |
icon | 32px (h-8 w-8) | Square icon-only button at md size. |
icon-sm | 28px (h-7 w-7) | Small square icon button. Used for inline edit/save icons on naked inputs and compact toolbar controls. |
icon-md | 32px (h-8 w-8) | Medium square icon button. Used for action bar icon menus (e.g. MoreVertical). |
import { Button } from '@repo/ui/components/button'
<Button>Save changes</Button> {/* md (default) */}
<Button variant="outline">Cancel</Button>
<Button variant="destructive">Delete project</Button>
<Button size="sm" variant="outline">Filter</Button>
<Button size="lg">Get Started</Button>
<Button size="icon-sm" variant="outline"><Pencil /></Button>
<Button size="icon-md" variant="ghost"><MoreVertical /></Button>Badge
Import: @repo/ui/components/badge
Status indicators, count chips, and classification tags. Renders as an inline-flex pill. All variants inherit the base size and border-radius — only color changes.
| Variant | Color | Use case |
|---|---|---|
default | Brand (solid) | Primary label, selected state |
secondary | Surface-300 background | Neutral metadata, normal priority |
outline | Border only | Subtle tags, assignee chips |
brand | Brand-200 background, brand-600 text | Project names, brand-associated labels |
success | Brand-200 background (alias of brand) | Completed state, positive outcomes |
warning | Warning-200 background, warning-600 text | High priority, caution states |
destructive | Destructive-200 background, destructive-600 text | Urgent priority, error states, deletion |
ghost | Surface-200 background, lighter text | Low priority, inactive or deprioritized labels |
import { Badge } from '@repo/ui/components/badge'
<Badge>Default</Badge>
<Badge variant="secondary">Normal</Badge>
<Badge variant="warning">High</Badge>
<Badge variant="destructive">Urgent</Badge>
<Badge variant="ghost">Low</Badge>
<Badge variant="brand">Project name</Badge>
<Badge variant="outline">Rick</Badge>For truncating text inside a badge (e.g. long project names), wrap the content in a span with truncate and constrain the badge with max-w-full:
<Badge variant="brand" className="max-w-full">
<span className="truncate">{projectName}</span>
</Badge>Input
Import: @repo/ui/components/input
Standard text input with brand-green focus ring. Uses border-border-control at rest and ring-2 ring-brand/40 border-brand on focus.
Naked Input
Import: @repo/ui/components/naked-input
A borderless inline-edit input that auto-sizes to its content width. Used for in-place editing of titles, names, and other text that should look like static text until clicked.
| Prop | Type | Description |
|---|---|---|
value | string | Current input value |
onChange | (value: string) => void | Called on every keystroke |
onSave | (value: string) => void | Called on blur, Enter, or Tab |
onCancel | () => void | Called on Escape |
inputClassName | string | Applied to both the input and the hidden sizer span for font matching |
Behavior:
- Auto-focuses on mount with cursor at end of text (not selecting all)
- Width auto-sizes to content via a hidden sizer
span - Transparent background, no border — blends with surrounding text
- Pair with a
Button size="icon-xs"for a save/cancel icon
import { NakedInput } from '@repo/ui/components/naked-input'
// Editing state
const [editing, setEditing] = useState(false)
const [draft, setDraft] = useState(project.name)
// In JSX — toggle between static text and naked input
{editing ? (
<NakedInput
value={draft}
onChange={setDraft}
onSave={handleSave}
onCancel={() => setEditing(false)}
inputClassName="text-xl font-medium text-foreground"
/>
) : (
<button onClick={() => setEditing(true)}>
{project.name}
<Button size="icon-sm" variant="outline">
<Pencil />
</Button>
</button>
)}Textarea
Import: @repo/ui/components/textarea
Same focus and border treatment as Input. Set rows for height.
Select
Import: @repo/ui/components/select
Radix Select with matching input styling. Exports: Select, SelectTrigger, SelectContent, SelectItem, SelectValue, SelectGroup, SelectSeparator.
Checkbox
Import: @repo/ui/components/checkbox
Radix Checkbox. Checked state uses bg-brand. Pair with a Label component using Radix's htmlFor / id pattern.
Switch
Import: @repo/ui/components/switch
Radix Switch. On state: bg-brand. Off: bg-surface-400.
Radio Group
Import: @repo/ui/components/radio-group
Exports: RadioGroup, RadioGroupItem.
Label
Import: @repo/ui/components/label
Radix Label. Automatically handles peer-disabled opacity. Always pair with form controls using matching id /htmlFor.
Card
Import: @repo/ui/components/card
Surface container using bg-surface-100 border-border. Exports: Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter.
Alert
Import: @repo/ui/components/alert
Callout boxes. Variants: default, info, success, warning, destructive. All use the corresponding -200 background with -600 text.
Skeleton
Import: @repo/ui/components/skeleton
Animated pulse loading placeholder. Use in place of content while data loads.
Progress
Import: @repo/ui/components/progress
Radix Progress with brand fill. Accepts a value prop (0–100).
Avatar
Import: @repo/ui/components/avatar
Radix Avatar with bg-brand-200 text-brand-600 fallback initials. Exports: Avatar, AvatarImage, AvatarFallback.
Dialog
Import: @repo/ui/components/dialog
Radix Dialog with bg-surface-100 background. Exports: Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, DialogTrigger.
Popover
Import: @repo/ui/components/popover
Radix Popover. bg-surface-100 border-border with slide-in animations. Exports: Popover, PopoverTrigger, PopoverContent, PopoverAnchor.
Tooltip
Import: @repo/ui/components/tooltip
Radix Tooltip. Dark bg-surface-400 background for contrast against light and dark surfaces. Wrap app root with TooltipProvider. Exports: Tooltip, TooltipTrigger, TooltipContent, TooltipProvider.
Tabs
Import: @repo/ui/components/tabs
Radix Tabs. Active tab: bg-background text-foregroundelevated on a bg-surface-200 pill background. Exports: Tabs, TabsList, TabsTrigger, TabsContent.
Accordion
Import: @repo/ui/components/accordion
Radix Accordion with CSS-variable-driven height animation (animate-accordion-down / animate-accordion-up). Requires the keyframes defined in admin's globals.css. Exports: Accordion, AccordionItem, AccordionTrigger, AccordionContent.
Table
Import: @repo/ui/components/table
Native HTML table with design token classes. Hover rows use bg-surface-200/50. Exports: Table, TableHeader, TableBody, TableRow, TableHead, TableCell, TableFooter, TableCaption.
Scroll Area
Import: @repo/ui/components/scroll-area
Radix ScrollArea. Styled scrollbar thumb using bg-border-strong. Exports: ScrollArea, ScrollBar.
Toggle
Import: @repo/ui/components/toggle
Radix Toggle. On state: bg-surface-300 text-foreground. Variants: default (transparent), outline(bordered).
Fragment patterns
Fragment components are higher-order patterns composed from atoms. They are built in each app rather than shared via @repo/ui since they are layout-specific. Common patterns:
- Page header — Breadcrumb + h1 + description + action button(s)
- Form item layout — Label + Input/Select + description + error message
- Confirmation modal — Dialog + destructive Button + cancel
- Data table — Table + sort headers + pagination
- Metric card — Card + large value + label + trend indicator
- Empty state — Icon + heading + description + CTA Button
Chart components
The chart library lives in @repo/ui alongside the atom components. It wraps recharts with consistent token-based styling and composable slot components. See the dedicated documentation pages for full API reference and usage examples.
- Charts —
ChartCard,BarChartCard,LineChartCard,LogsBarChart,ChartTooltip - Metric Cards —
MetricCard,MetricCardValue,MetricCardDifferential,MetricCardSparkline