Skip to content

shadcn Components

Component inventory, import paths, and migration rules for all shadcn/ui and custom components available in the main app.


ComponentImportNotes
Alert, AlertTitle, AlertDescription@/components/ui/alertCVA variants: default, destructive
AlertDialog + sub-components@/components/ui/alert-dialogConfirm/destructive dialogs
Avatar, AvatarImage, AvatarFallback@/components/ui/avatar
Badge@/components/ui/badgeVariants: default, secondary, destructive, outline
Button@/components/ui/buttonVariants: default, outline, ghost, destructive; sizes: sm, lg, icon, xs, icon-xs, icon-sm, icon-lg
Calendar@/components/ui/calendarWraps react-day-picker
Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter@/components/ui/card
Checkbox@/components/ui/checkboxUse onCheckedChange, not onChange
Dialog + sub-components@/components/ui/dialog
DropdownMenu + sub-components@/components/ui/dropdown-menu
Form + sub-components@/components/ui/formWraps react-hook-form
Input@/components/ui/input
InputOTP + sub-components@/components/ui/input-otpWraps input-otp package
Label@/components/ui/label
RadioGroup, RadioGroupItem@/components/ui/radio-group
ScrollArea, ScrollBar@/components/ui/scroll-area
Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGroup, SelectLabel, SelectSeparator@/components/ui/selectUse onValueChange, not onChange
Separator@/components/ui/separator
Sheet + sub-components@/components/ui/sheet
Skeleton@/components/ui/skeleton
Sonner (toast)@/components/ui/sonner
Switch@/components/ui/switch
Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption@/components/ui/table
Tabs, TabsList, TabsTrigger, TabsContent@/components/ui/tabs
Textarea@/components/ui/textarea
Tooltip, TooltipProvider, TooltipTrigger, TooltipContent@/components/ui/tooltip

TanStack Table suite. All exported from @/components/data-table.

ExportFilePurpose
DataTableColumnHeadercolumn-header.tsxSortable column header with sort icons
DataTablePaginationpagination.tsxPage size + prev/next controls
DataTableToolbartoolbar.tsxSearch input + faceted filters + view options
DataTableBulkActionsbulk-actions.tsxFloating bulk-action toolbar
DataTableFacetedFilterfaceted-filter.tsxPopover with Command for multi-select filtering
DataTableViewOptionsview-options.tsxColumn visibility toggle dropdown

ComponentImportProps
ConfirmDialog@/components/confirm-dialogopen, onOpenChange, title, desc, handleConfirm, destructive?, isLoading?, cancelBtnText?, confirmText?
DatePicker@/components/date-pickerPopover wrapping Calendar; uses date-fns format
PasswordInput@/components/password-inputInput with Eye/EyeOff toggle
SelectDropdown@/components/select-dropdownSelect with loading state + FormControl integration
LongText@/components/long-textTruncated text; Tooltip on desktop, Popover on mobile
SkipToMain@/components/skip-to-mainAccessibility skip link
ComingSoon@/components/coming-soonPlaceholder page with Telescope icon

Layout Components — src/components/layout/

Section titled “Layout Components — src/components/layout/”
ComponentImportNotes
Header@/components/layout/headerScroll-aware sticky header; accepts fixed prop; uses SidebarTrigger + Separator
Main@/components/layout/main<main> wrapper; fixed prop for flex overflow layout; fluid prop disables max-width centering
AppTitle@/components/layout/app-titleBranding component with name and description props
TopNav@/components/layout/top-navResponsive nav: mobile dropdown + desktop inline links; accepts links array with title, href, isActive, disabled?

Cinatra uses the consolidated radix-ui package, not individual @radix-ui/react-* packages:

// Correct
import { Dialog as DialogPrimitive, Checkbox as CheckboxPrimitive } from "radix-ui";
// Wrong — do not use
import * as DialogPrimitive from "@radix-ui/react-dialog";

When replacing raw HTML form elements with shadcn components:

Raw HTMLshadcn componentKey change
<button className="ink-button"><Button>default variant
<button className="cream-button"> or outline-style<Button variant="outline">
<button className="ghost-button"><Button variant="ghost">
<button className="destructive-button"><Button variant="destructive">
<input className="..."><Input>preserve type, all props
<textarea className="..."><Textarea>preserve rows, all props
<select onChange={fn}><Select onValueChange={fn}>onValueChange, not onChange; value on <Select> for controlled
<input type="checkbox" onChange={fn}><Checkbox onCheckedChange={fn}>onCheckedChange, not onChange
<label><Label>preserve htmlFor
Status <span> with color classes<Badge variant="...">green→default, red→destructive, gray→secondary, outlined→outline
<table>/<thead>/<tbody>/<tr>/<th>/<td><Table>/<TableHeader>/<TableBody>/<TableRow>/<TableHead>/<TableCell>

Keep native <select> and <input type="checkbox"> as raw HTML when they are inside a server action <form> with a name attribute. Radix/shadcn wrappers are not form-associated elements — they will not appear in FormData, silently breaking form submissions.

// Inside a server action form — keep native:
<form action={myServerAction}>
<select name="outputFormat" defaultValue="json">
<option value="json">JSON</option>
<option value="csv">CSV</option>
</select>
<input type="checkbox" name="enabled" defaultChecked={isEnabled} />
</form>

When migrating buttons to shadcn Button, delete any local helper functions that were used to build button class strings (buttonClassName(), stepButtonClassName(), inkButtonClassName(), etc.). These become dead code after migration and must be removed — do not leave them as unused exports. If the helper was exported and consumed by other files, migrate those call sites first, then delete the helper.

When a <Link> is styled to look like a button, use the asChild prop:

import { Button } from "@/components/ui/button";
import Link from "next/link";
<Button asChild>
<Link href="/new">Create</Link>
</Button>
<Button variant="outline" asChild>
<Link href="/edit">Edit</Link>
</Button>

These were added to src/app/globals.css alongside the component migration:

  • @utility no-scrollbar — hides scrollbar cross-browser
  • @utility faded-bottom — gradient fade at scroll bottom
  • @import "tw-animate-css" — provides animate-in, fade-in-0, zoom-in-95, slide-in-from-* used by Radix popover/dialog transitions
  • Collapsible keyframes: slideDown / slideUp / .animate-slideDown / .animate-slideUp
  • Chart tokens: --chart-1 through --chart-5 (OKLch values)
  • Font variables: --font-inter, --font-manrope

  • ~/.claude/skills/shadcn — the canonical shadcn skill, surfaced through the Claude Code skill loader (symlink to ~/.agents/skills/shadcn). Contains SKILL.md, the rule files in rules/ (base-vs-radix.md, composition.md, forms.md, icons.md, styling.md), plus customization.md, cli.md, and mcp.md. The shadcn skill activates automatically when components.json is present at the project root, so component generation, customization, and migration follow shadcn-blessed defaults out of the box.
  • .planning/audits/UI-AUDIT.md — the v3.0 UI Compliance audit row-store (created in Phase 225). Each violation is a row in audit-rows.tsv; UI-AUDIT.md renders the human-readable view, scoped by section (html, color, space, dark, zindex-overlay-managed, zindex-layout-layer, arbitrary-color, shell, compose, icon, scope-badge, primitive). Run node scripts/audit/ui-violations.mjs --section={…} [--strict] [--json] to query; node scripts/audit/done-when-mapping-check.mjs validates every Done-when checklist marker against ROADMAP. v3.0 base seed posture: every row status=exempt (per CONTEXT.md D-225-01); downstream phases (226–229) flip rows to closed as they land their sweeps.
  • AGENTS.md → “Frontend / UI development” → “Forbidden patterns” — the eleven non-negotiable forbidden-pattern rules for UI work. Audit rows reference this section by heading anchor (AGENTS.md#frontend--ui-development--forbidden-patterns) for rule_ref traceability.