Cookest
UI Components

Components

API reference for all 50 CUCL components β€” props, variants, and usage examples

Components

All components are exported from @cookest/ui. Each one is fully typed, dark-mode-aware, and accessible by default.

import {
  Accordion, Alert, AlertDialog, AspectRatio, Avatar, Badge, Breadcrumb, Button,
  Calendar, Card, Carousel, ChartContainer, Checkbox, Collapsible, Command,
  ContextMenu, Dialog, Divider, Drawer, DropdownMenu, Form, HoverCard, Input,
  InputOTP, Label, Menubar, Modal, NavigationMenu, Pagination, Popover, Progress,
  RadioGroup, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea,
  Separator, Sheet, Sidebar, Skeleton, Slider, SonnerToaster, Spinner, Switch,
  Table, Tabs, Textarea, Toast, Toaster, Toggle, ToggleGroup, Tooltip,
} from "@cookest/ui";
import "@cookest/ui/styles.css";

Compound APIs expose additional helpers such as DialogContent, SheetTrigger, FormField, TableHead, and useToast. Each section below calls out the extra exports that belong to that component family.


Button

Animated button with four variants and a built-in loading spinner.

Props

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "danger""primary"Visual style
size"sm" | "md" | "lg""md"Button size
loadingbooleanfalseShows spinner and disables the button
iconLeftReactNodeβ€”Icon rendered before the label
iconRightReactNodeβ€”Icon rendered after the label
fullWidthbooleanfalseStretches to fill its container
disabledbooleanfalseNative disabled attribute
classNamestringβ€”Additional Tailwind classes

All standard <button> HTML attributes are forwarded.

Examples

// Variants
<Button variant="primary">Save changes</Button>
<Button variant="secondary">Cancel</Button>
<Button variant="ghost">Learn more</Button>
<Button variant="danger">Delete account</Button>

// Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

// Loading state
<Button loading>Saving…</Button>

// Icon slots
<Button iconLeft={<PlusIcon />}>Add item</Button>
<Button iconRight={<ArrowRightIcon />}>Continue</Button>

The button uses motion.button from Framer Motion β€” it lifts 1px on hover and scales to 0.98 on press. Animations are suppressed when disabled or loading is true.


Input

Text input with label, helper text, error state, and icon slots.

Props

PropTypeDefaultDescription
labelstringβ€”Label text rendered above the input
helperTextstringβ€”Helper text rendered below
errorstringβ€”Error message β€” replaces helperText and styles the border red
iconLeftReactNodeβ€”Icon in the left slot
iconRightReactNodeβ€”Icon in the right slot
inputSize"sm" | "md" | "lg""md"Input size (uses inputSize to avoid clash with HTML size)
fullWidthbooleanfalseStretches to container width
classNamestringβ€”Applied to the outer wrapper

All standard <input> HTML attributes are forwarded. id is auto-generated if not provided.

Examples

// Basic
<Input label="Email" type="email" placeholder="you@example.com" />

// With helper text
<Input label="Username" helperText="3–20 characters, lowercase only" />

// Error state
<Input label="Password" type="password" error="Minimum 8 characters required" />

// Icon slots
<Input label="Search" iconLeft={<SearchIcon />} placeholder="Search recipes…" />

// Full-width
<Input label="Name" fullWidth />

Card

Container component with optional header, body, and footer sections.

Card props

PropTypeDefaultDescription
variant"default" | "interactive" | "outlined""default"Visual style β€” interactive adds hover animation
padding"none" | "sm" | "md" | "lg""md"Uniform inner padding
classNamestringβ€”Additional classes

Sub-components

CardHeader, CardBody, and CardFooter are used for structured layouts. They manage their own border and padding β€” do not add padding to the parent Card when using sub-components (padding="none").

Examples

// Simple card with padding
<Card>
  <p>Card content</p>
</Card>

// Structured card
<Card padding="none">
  <CardHeader>Recipe Details</CardHeader>
  <CardBody>
    <p>Ingredients and steps…</p>
  </CardBody>
  <CardFooter>
    <Button>Start cooking</Button>
  </CardFooter>
</Card>

// Interactive card (hover lift)
<Card variant="interactive" onClick={handleClick}>
  <p>Click me</p>
</Card>

Badge

Compact status indicator with optional dot and remove button.

Props

PropTypeDefaultDescription
variant"default" | "success" | "warning" | "error" | "info""default"Colour variant
size"sm" | "md" | "lg""md"Badge size
dotbooleanfalseShows a colour dot before the label
removablebooleanfalseShows a remove (Γ—) button
onRemove() => voidβ€”Called when the remove button is clicked
classNamestringβ€”Additional classes

Examples

<Badge variant="success">Active</Badge>
<Badge variant="warning" dot>Expiring soon</Badge>
<Badge variant="error" size="sm">Out of stock</Badge>
<Badge removable onRemove={() => removeTag(id)}>Vegan</Badge>

Avatar

User avatar with image, initials fallback, and group stacking.

Avatar props

PropTypeDefaultDescription
srcstringβ€”Image URL β€” renders <img> when provided
altstringrequiredAlt text (also used to derive initials)
initialsstringβ€”Override auto-derived initials
size"xs" | "sm" | "md" | "lg" | "xl""md"Avatar size
classNamestringβ€”Additional classes

When src is absent the component renders a <span> with the first two initials on a sage green background.

AvatarGroup props

PropTypeDefaultDescription
maxnumberβ€”Maximum avatars to show β€” overflow rendered as +N
childrenReactNoderequiredAvatar components
classNamestringβ€”Additional classes

Examples

// With image
<Avatar src="/users/alice.jpg" alt="Alice Smith" size="lg" />

// Initials fallback
<Avatar alt="Bob Jones" size="md" />

// Group
<AvatarGroup max={3}>
  <Avatar alt="Alice Smith" />
  <Avatar alt="Bob Jones" />
  <Avatar alt="Carol White" />
  <Avatar alt="Dave Green" />
</AvatarGroup>

Accessible dialog overlay with focus trap and keyboard dismiss.

Props

PropTypeDefaultDescription
openbooleanrequiredControls visibility
onClose() => voidrequiredCalled when dismissed
titlestringβ€”Renders a header row with close button
size"sm" | "md" | "lg""md"Dialog max-width
closeOnBackdropbooleantrueDismiss when clicking the backdrop
closeOnEscbooleantrueDismiss on Escape key
footerReactNodeβ€”Content in the footer row
classNamestringβ€”Applied to the dialog panel

Example

const [open, setOpen] = useState(false);

<Button onClick={() => setOpen(true)}>Open modal</Button>

<Modal
  open={open}
  onClose={() => setOpen(false)}
  title="Confirm deletion"
  footer={
    <>
      <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
      <Button variant="danger" onClick={handleDelete}>Delete</Button>
    </>
  }
>
  <p>This action cannot be undone.</p>
</Modal>

The Modal manages document.body.style.overflow to prevent scroll while open and restores focus to the previously active element on close.


Tooltip

Positioned tooltip with an animated arrow.

Props

PropTypeDefaultDescription
contentReactNoderequiredTooltip text or JSX
position"top" | "bottom" | "left" | "right""top"Arrow direction
delaynumber0Show delay in milliseconds
classNamestringβ€”Applied to the tooltip panel
childrenReactNoderequiredTrigger element

Example

<Tooltip content="Save your changes" position="top">
  <Button variant="ghost" size="sm">
    <SaveIcon />
  </Button>
</Tooltip>

Toggle

Switch input with an optional label.

Props

PropTypeDefaultDescription
checkedbooleanrequiredToggle state
onChange(checked: boolean) => voidrequiredState change handler
labelstringβ€”Label text
size"sm" | "md" | "lg""md"Toggle size
disabledbooleanfalsePrevents interaction
classNamestringβ€”Additional classes

Example

const [enabled, setEnabled] = useState(false);

<Toggle
  checked={enabled}
  onChange={setEnabled}
  label="Enable notifications"
/>

Select

Custom dropdown with keyboard navigation and optional search.

Props

PropTypeDefaultDescription
optionsSelectOption[]requiredArray of { value, label, disabled? }
valuestringβ€”Controlled selected value
onChange(value: string) => voidβ€”Selection handler
placeholderstring"Select…"Placeholder text
labelstringβ€”Label above the trigger
errorstringβ€”Error message below
disabledbooleanfalsePrevents interaction
searchablebooleanfalseAdds a search input inside the dropdown
classNamestringβ€”Applied to the wrapper

Example

const [diet, setDiet] = useState("");

<Select
  label="Dietary preference"
  options={[
    { value: "none", label: "No preference" },
    { value: "vegan", label: "Vegan" },
    { value: "vegetarian", label: "Vegetarian" },
    { value: "gluten-free", label: "Gluten-free" },
  ]}
  value={diet}
  onChange={setDiet}
  searchable
/>

Skeleton

Loading placeholder with a pulse animation.

Skeleton props

PropTypeDefaultDescription
variant"text" | "circular" | "rectangular""rectangular"Shape
widthstring | numberβ€”CSS width value or px number
heightstring | numberβ€”CSS height value or px number
linesnumber1Number of text lines (variant="text" only)
classNamestringβ€”Additional classes

SkeletonCard

Pre-built card skeleton for loading states:

<SkeletonCard />

Examples

// Text lines
<Skeleton variant="text" lines={3} />

// Avatar placeholder
<Skeleton variant="circular" width={40} height={40} />

// Image placeholder
<Skeleton variant="rectangular" width="100%" height={200} />

// Full card
<SkeletonCard />

Alert

Contextual feedback banner with animated entrance and dismiss.

Props

PropTypeDefaultDescription
variant"info" | "success" | "warning" | "error""info"Colour and icon variant
titlestringβ€”Bold title row
dismissiblebooleanfalseShows a dismiss (Γ—) button
onDismiss() => voidβ€”Called when dismissed
iconReactNodeβ€”Override the default variant icon
visiblebooleantrueControls AnimatePresence visibility
classNamestringβ€”Additional classes

Examples

// Static info banner
<Alert variant="info" title="Did you know?">
  You can save up to 20% by switching to the Pro plan.
</Alert>

// Dismissible error
const [show, setShow] = useState(true);
<Alert
  variant="error"
  title="Upload failed"
  dismissible
  visible={show}
  onDismiss={() => setShow(false)}
>
  The file exceeds the 10 MB limit.
</Alert>

Divider

Visual separator, horizontal or vertical.

Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Axis
labelstringβ€”Centered label text (horizontal only)
classNamestringβ€”Additional classes

Examples

// Horizontal
<Divider />

// With label
<Divider label="or continue with" />

// Vertical (needs a fixed height context)
<div className="flex h-8 items-center gap-4">
  <span>Option A</span>
  <Divider orientation="vertical" />
  <span>Option B</span>
</div>

Accordion

Data-driven accordion for FAQs, settings groups, and expandable content blocks.

Import

import { Accordion } from "@cookest/ui";

Props

PropTypeDefaultDescription
itemsAccordionItem[]requiredArray of sections to render
defaultOpenstring | string[]β€”Initially open item ID(s)
multiplebooleanfalseAllow more than one open item
variant"default" | "bordered" | "separated""default"Visual style
size"sm" | "md" | "lg""md"Header/content sizing
classNamestringβ€”Wrapper classes

AccordionItem has the shape { id, title, subtitle?, icon?, content, disabled? }.

Example

<Accordion
  items={[
    {
      id: "pantry",
      title: "Pantry sync",
      subtitle: "2 items expiring soon",
      content: <p>Your pantry data syncs automatically.</p>,
    },
  ]}
  defaultOpen="pantry"
/>

AlertDialog

Confirmation dialog for destructive or high-stakes actions.

Import

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
AlertDialogReact.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Root>Root open-state container
AlertDialogContentReact.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>Main dialog surface
AlertDialogTitleReact.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>Title text
AlertDialogDescriptionReact.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>Supporting copy
AlertDialogActionReact.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>Primary action button
AlertDialogCancelReact.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>Secondary cancel button

Example

<AlertDialog>
  <AlertDialogTrigger asChild>
    <Button variant="danger">Delete recipe</Button>
  </AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Delete this recipe?</AlertDialogTitle>
      <AlertDialogDescription>
        This action cannot be undone.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction>Delete</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>

AspectRatio

Keeps media, embeds, and cards locked to a specific ratio.

Import

import { AspectRatio } from "@cookest/ui";

Props

ExportProps typeNotes
AspectRatioReact.ComponentPropsWithoutRef<typeof AspectRatioPrimitive.Root>Use the Radix ratio prop to control width/height proportion

Example

<AspectRatio ratio={16 / 9}>
  <img src="/recipe.jpg" alt="Recipe" className="h-full w-full rounded-lg object-cover" />
</AspectRatio>

Hierarchical navigation trail for dashboards and deep flows.

Import

import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@cookest/ui";

Props

ExportProps typeNotes
BreadcrumbReact.ComponentPropsWithoutRef<"nav"> & { separator?: React.ReactNode }Wraps the breadcrumb nav landmark
BreadcrumbLinkReact.ComponentPropsWithoutRef<"a"> & { asChild?: boolean }Supports Radix Slot composition
BreadcrumbSeparatorReact.ComponentProps<"li">Defaults to a chevron separator
BreadcrumbEllipsisReact.ComponentProps<"span">Compact overflow marker

Example

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/docs">Docs</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Components</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

Calendar

Themed react-day-picker wrapper for single, range, or multi-date selection.

Import

import { Calendar } from "@cookest/ui";

Props

PropTypeDefaultDescription
showOutsideDaysbooleantrueShow leading/trailing days from adjacent months
classNamestringβ€”Outer wrapper classes
classNamesCalendarProps["classNames"]β€”Override internal DayPicker class mappings
...propsReact.ComponentProps<typeof DayPicker>β€”All native react-day-picker props are forwarded

Example

const [selected, setSelected] = useState<Date | undefined>(new Date());

<Calendar mode="single" selected={selected} onSelect={setSelected} />

Embla-powered carousel with built-in navigation buttons and orientation support.

Import

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from "@cookest/ui";

Props

PropTypeDefaultDescription
optsCarouselOptionsβ€”Embla carousel configuration
pluginsCarouselPluginβ€”Embla plugins array
orientation"horizontal" | "vertical""horizontal"Slide axis
setApi(api: CarouselApi) => voidβ€”Receive the Embla API instance
...propsReact.HTMLAttributes<HTMLDivElement>β€”Standard wrapper props

CarouselPrevious and CarouselNext also accept Button props (minus required children).

Example

<Carousel className="w-full max-w-md">
  <CarouselContent>
    {[1, 2, 3].map((item) => (
      <CarouselItem key={item}>
        <Card>
          <p>Slide {item}</p>
        </Card>
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>

Chart

Recharts helpers for theme-aware chart containers, tooltips, and legends.

Import

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
} from "@cookest/ui";

Props

ExportProps typeNotes
ChartContainerReact.ComponentProps<"div"> & { config: ChartConfig; children: ResponsiveContainer["children"] }Provides chart theme/config context
ChartTooltiptypeof RechartsPrimitive.TooltipRe-exported Recharts tooltip primitive
ChartTooltipContentReact.ComponentProps<typeof RechartsPrimitive.Tooltip> & React.ComponentProps<"div"> & { hideLabel?: boolean; hideIndicator?: boolean; indicator?: "line" | "dot" | "dashed"; nameKey?: string; labelKey?: string }Styled tooltip renderer
ChartLegendtypeof RechartsPrimitive.LegendRe-exported Recharts legend primitive
ChartLegendContentReact.ComponentProps<"div"> & Pick<LegendProps, "payload" | "verticalAlign"> & { hideIcon?: boolean; nameKey?: string }Styled legend renderer

ChartConfig maps series keys to labels, icons, and colors/theme overrides.

Example

import { Bar, BarChart, XAxis } from "recharts";

const chartConfig = {
  protein: { label: "Protein", color: "#7A9A65" },
};

<ChartContainer config={chartConfig} className="h-64">
  <BarChart data={[{ day: "Mon", protein: 24 }]}>
    <XAxis dataKey="day" />
    <ChartTooltip content={<ChartTooltipContent />} />
    <ChartLegend content={<ChartLegendContent />} />
    <Bar dataKey="protein" fill="var(--color-protein)" />
  </BarChart>
</ChartContainer>

Checkbox

Accessible checkbox built on Radix with checked and indeterminate support.

Import

import { Checkbox } from "@cookest/ui";

Props

ExportProps typeNotes
CheckboxReact.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>Supports checked, defaultChecked, onCheckedChange, disabled, and other Radix checkbox props

Example

<Checkbox checked={checked} onCheckedChange={setChecked} aria-label="Select ingredient" />

Collapsible

Lightweight expandable container for inline disclosure UI.

Import

import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@cookest/ui";

Props

ExportProps typeNotes
CollapsibleReact.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Root>Controls open state
CollapsibleTriggerReact.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleTrigger>Toggle control
CollapsibleContentReact.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent>Expandable body

Example

<Collapsible>
  <CollapsibleTrigger asChild>
    <Button variant="ghost">Show nutrition notes</Button>
  </CollapsibleTrigger>
  <CollapsibleContent>
    <p>Extra nutritional guidance goes here.</p>
  </CollapsibleContent>
</Collapsible>

Command

Command palette and searchable action list powered by cmdk.

Import

import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandShortcut,
} from "@cookest/ui";

Props

ExportProps typeNotes
CommandReact.ComponentPropsWithoutRef<typeof CommandPrimitive>Root command surface
CommandDialogReact.ComponentPropsWithoutRef<typeof Dialog>Wraps the command list inside the CUCL Dialog
CommandInputReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>Search field
CommandItemReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>Selectable result row
CommandShortcutReact.HTMLAttributes<HTMLSpanElement>Right-aligned shortcut text

Example

<CommandDialog open={open} onOpenChange={setOpen}>
  <CommandInput placeholder="Search actions..." />
  <CommandList>
    <CommandEmpty>No results.</CommandEmpty>
    <CommandGroup heading="Recipes">
      <CommandItem>
        Generate recipe
        <CommandShortcut>⌘K</CommandShortcut>
      </CommandItem>
    </CommandGroup>
  </CommandList>
</CommandDialog>

ContextMenu

Right-click or long-press menu for contextual actions.

Import

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
ContextMenuReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Root>Root state container
ContextMenuContentReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>Floating menu surface
ContextMenuItemReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & { inset?: boolean }Optional inset padding
ContextMenuSubTriggerReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & { inset?: boolean }Opens a submenu
ContextMenuLabelReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & { inset?: boolean }Section label
ContextMenuShortcutReact.HTMLAttributes<HTMLSpanElement>Keyboard shortcut label

Example

<ContextMenu>
  <ContextMenuTrigger asChild>
    <Card>
      <p>Right-click this card</p>
    </Card>
  </ContextMenuTrigger>
  <ContextMenuContent>
    <ContextMenuItem>Rename</ContextMenuItem>
    <ContextMenuItem>Duplicate</ContextMenuItem>
  </ContextMenuContent>
</ContextMenu>

Dialog

Radix-based modal dialog for fully custom overlays.

Import

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
DialogReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Root>Root open-state container
DialogContentReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>Main dialog surface
DialogHeaderReact.HTMLAttributes<HTMLDivElement>Header layout helper
DialogFooterReact.HTMLAttributes<HTMLDivElement>Footer action row
DialogTitleReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>Title text
DialogDescriptionReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>Description text

Example

<Dialog>
  <DialogTrigger asChild>
    <Button>Open dialog</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Share recipe</DialogTitle>
      <DialogDescription>Copy a link or invite collaborators.</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <Button>Done</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Drawer

Bottom-sheet style panel powered by vaul.

Import

import {
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
DrawerReact.ComponentProps<typeof DrawerPrimitive.Root>shouldScaleBackground defaults to true
DrawerContentReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>Bottom sheet surface
DrawerHeaderReact.HTMLAttributes<HTMLDivElement>Header layout helper
DrawerFooterReact.HTMLAttributes<HTMLDivElement>Footer action stack
DrawerTitleReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>Title text
DrawerDescriptionReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>Supporting copy

Example

<Drawer>
  <DrawerTrigger asChild>
    <Button>Open drawer</Button>
  </DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Quick actions</DrawerTitle>
      <DrawerDescription>Choose the next step.</DrawerDescription>
    </DrawerHeader>
    <DrawerFooter>
      <Button>Continue</Button>
    </DrawerFooter>
  </DrawerContent>
</Drawer>

Button-triggered action menu with checkbox, radio, and submenu support.

Import

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
DropdownMenuReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>Root menu state
DropdownMenuContentReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>sideOffset defaults to 4
DropdownMenuItemReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }Optional inset padding
DropdownMenuSubTriggerReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }Opens nested menus
DropdownMenuLabelReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }Section label
DropdownMenuShortcutReact.HTMLAttributes<HTMLSpanElement>Shortcut text slot

Example

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="ghost">Open menu</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem>Edit</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem>Delete</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Form

Helpers for pairing react-hook-form with CUCL inputs and accessible field messaging.

Import

import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@cookest/ui";

Props

ExportProps typeNotes
Formtypeof FormProviderWraps the React Hook Form context
FormFieldControllerProps<TFieldValues, TName>Connects a single controlled field
FormItemReact.HTMLAttributes<HTMLDivElement>Provides IDs for label/description/message wiring
FormLabelReact.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>Label tied to the current FormField
FormControlReact.ComponentPropsWithoutRef<typeof Slot>Injects ARIA attributes into the control
FormDescriptionReact.HTMLAttributes<HTMLParagraphElement>Help text
FormMessageReact.HTMLAttributes<HTMLParagraphElement>Validation error text

Example

const form = useForm({ defaultValues: { email: "" } });

<Form {...form}>
  <form onSubmit={form.handleSubmit(console.log)}>
    <FormField
      control={form.control}
      name="email"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Email</FormLabel>
          <FormControl>
            <Input type="email" {...field} />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
  </form>
</Form>

HoverCard

Preview card that appears on hover or focus.

Import

import { HoverCard, HoverCardContent, HoverCardTrigger } from "@cookest/ui";

Props

ExportProps typeNotes
HoverCardReact.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root>Root state container
HoverCardTriggerReact.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger>Trigger element
HoverCardContentReact.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>align="center" and sideOffset={4} by default

Example

<HoverCard>
  <HoverCardTrigger asChild>
    <Button variant="ghost">Hover for preview</Button>
  </HoverCardTrigger>
  <HoverCardContent>
    <p>Quick recipe summary.</p>
  </HoverCardContent>
</HoverCard>

InputOTP

Segmented one-time-password input built on input-otp.

Import

import {
  InputOTP,
  InputOTPGroup,
  InputOTPSeparator,
  InputOTPSlot,
} from "@cookest/ui";

Props

ExportProps typeNotes
InputOTPReact.ComponentPropsWithoutRef<typeof OTPInput>Also supports containerClassName styling
InputOTPGroupReact.ComponentPropsWithoutRef<"div">Groups slots visually
InputOTPSlotReact.ComponentPropsWithoutRef<"div"> & { index: number }Slot renderer for a specific position
InputOTPSeparatorReact.ComponentPropsWithoutRef<"div">Visual separator between groups

Example

<InputOTP maxLength={6} value={code} onChange={setCode}>
  <InputOTPGroup>
    <InputOTPSlot index={0} />
    <InputOTPSlot index={1} />
    <InputOTPSlot index={2} />
  </InputOTPGroup>
  <InputOTPSeparator />
  <InputOTPGroup>
    <InputOTPSlot index={3} />
    <InputOTPSlot index={4} />
    <InputOTPSlot index={5} />
  </InputOTPGroup>
</InputOTP>

Label

Form label primitive with disabled-peer styling.

Import

import { Label } from "@cookest/ui";

Props

ExportProps typeNotes
LabelReact.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>Forwarded Radix label props

Example

<Label htmlFor="servings">Servings</Label>

Desktop-style menubar with submenus, checkbox items, and radio groups.

Import

import {
  Menubar,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
MenubarReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>Top-level menubar container
MenubarContentReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>Defaults: align="start", alignOffset={-4}, sideOffset={8}
MenubarItemReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & { inset?: boolean }Menu row with optional inset
MenubarSubTriggerReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean }Opens a submenu
MenubarLabelReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & { inset?: boolean }Group label
MenubarShortcutReact.HTMLAttributes<HTMLSpanElement>Shortcut text slot

Example

<Menubar>
  <MenubarMenu>
    <MenubarTrigger>File</MenubarTrigger>
    <MenubarContent>
      <MenubarItem>New recipe</MenubarItem>
      <MenubarItem>Export</MenubarItem>
    </MenubarContent>
  </MenubarMenu>
</Menubar>

Navigation bar primitive for multi-level site or dashboard menus.

Import

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
NavigationMenuReact.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>Root wrapper that also renders the viewport
NavigationMenuListReact.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>Horizontal item list
NavigationMenuTriggerReact.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>Trigger button for content
NavigationMenuContentReact.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>Dropdown content panel
navigationMenuTriggerStylestringShared trigger class string for custom link implementations

Example

<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Docs</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink href="/docs/backend">Backend</NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>

Pagination

Composable pagination navigation with previous/next links and ellipsis helpers.

Import

import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@cookest/ui";

Props

ExportProps typeNotes
PaginationReact.ComponentProps<"nav">Root nav landmark
PaginationContentReact.ComponentProps<"ul">Inner list wrapper
PaginationItemReact.ComponentProps<"li">Single list item
PaginationLinkReact.ComponentProps<"a"> & Pick<ButtonProps, "size"> & { isActive?: boolean }Page link styled like a button
PaginationPreviousReact.ComponentProps<typeof PaginationLink>Previous shortcut
PaginationNextReact.ComponentProps<typeof PaginationLink>Next shortcut

Example

<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious href="?page=1" />
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="?page=2" isActive>
        2
      </PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext href="?page=3" />
    </PaginationItem>
  </PaginationContent>
</Pagination>

Popover

Floating panel anchored to a trigger or custom anchor.

Import

import { Popover, PopoverContent, PopoverTrigger } from "@cookest/ui";

Props

ExportProps typeNotes
PopoverReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root>Root state container
PopoverTriggerReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>Trigger element
PopoverAnchorReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Anchor>Optional custom anchor
PopoverContentReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>Defaults: align="center", sideOffset={4}

Example

<Popover>
  <PopoverTrigger asChild>
    <Button variant="ghost">Open popover</Button>
  </PopoverTrigger>
  <PopoverContent>
    <p>Popover content</p>
  </PopoverContent>
</Popover>

Progress

Linear progress indicator with labels, variants, and optional animation.

Import

import { Progress } from "@cookest/ui";

Props

PropTypeDefaultDescription
valuenumberβ€”Current progress value
labelstringβ€”Optional label above the bar
showValuebooleanfalseDisplay the numeric value
size"xs" | "sm" | "md" | "lg""md"Track height
color"primary" | "success" | "warning" | "error""primary"Bar color
stripedbooleanfalseApply striped fill styling
animatedbooleanfalseAnimate stripes
roundedbooleantrueRound the bar corners
classNamestringβ€”Wrapper classes

Example

<Progress value={72} label="Meal plan completion" showValue color="success" />

RadioGroup

Single-selection option group built on Radix radio primitives.

Import

import { RadioGroup, RadioGroupItem } from "@cookest/ui";

Props

ExportProps typeNotes
RadioGroupReact.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>Supports controlled and uncontrolled selection
RadioGroupItemReact.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>Individual option

Example

<RadioGroup value={planType} onValueChange={setPlanType}>
  <div className="flex items-center gap-2">
    <RadioGroupItem value="balanced" id="balanced" />
    <Label htmlFor="balanced">Balanced</Label>
  </div>
</RadioGroup>

Resizable

Composable panel layout powered by react-resizable-panels.

Import

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@cookest/ui";

Props

ExportProps typeNotes
ResizablePanelGroupReact.ComponentProps<typeof Group>orientation defaults to "horizontal"
ResizablePaneltypeof PanelIndividual resizable panel
ResizableHandleReact.ComponentProps<typeof Separator> & { withHandle?: boolean }Divider between panels; optional visible grab handle

Example

<ResizablePanelGroup className="min-h-[320px] rounded-lg border">
  <ResizablePanel defaultSize={35}>Filters</ResizablePanel>
  <ResizableHandle withHandle />
  <ResizablePanel defaultSize={65}>Results</ResizablePanel>
</ResizablePanelGroup>

ScrollArea

Custom scroll container with themed scrollbars.

Import

import { ScrollArea, ScrollBar } from "@cookest/ui";

Props

ExportProps typeNotes
ScrollAreaReact.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>Root scroll viewport
ScrollBarReact.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>Custom scrollbar

Example

<ScrollArea className="h-48 rounded-md border p-4">
  <div className="space-y-2">...</div>
  <ScrollBar orientation="vertical" />
</ScrollArea>

Separator

Minimal separator primitive for layout composition.

Import

import { Separator } from "@cookest/ui";

Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Axis
decorativebooleantrueMarks the separator as presentational
classNamestringβ€”Additional classes
...propsReact.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>β€”Forwarded Radix separator props

Example

<div className="flex h-8 items-center gap-4">
  <span>Left</span>
  <Separator orientation="vertical" />
  <span>Right</span>
</div>

Sheet

Side panel built on the Radix dialog primitives.

Import

import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
SheetReact.ComponentPropsWithoutRef<typeof SheetPrimitive.Root>Root open-state container
SheetContentReact.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & { side?: "top" | "right" | "bottom" | "left" }side defaults to "right"
SheetHeaderReact.HTMLAttributes<HTMLDivElement>Header layout helper
SheetFooterReact.HTMLAttributes<HTMLDivElement>Footer action row
SheetTitleReact.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>Title text
SheetDescriptionReact.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>Supporting copy

Example

<Sheet>
  <SheetTrigger asChild>
    <Button>Open sheet</Button>
  </SheetTrigger>
  <SheetContent side="right">
    <SheetHeader>
      <SheetTitle>Recipe filters</SheetTitle>
      <SheetDescription>Adjust cuisine and time limits.</SheetDescription>
    </SheetHeader>
  </SheetContent>
</Sheet>

Responsive application sidebar with mobile-sheet fallback and rich menu helpers.

Import

import {
  Sidebar,
  SidebarContent,
  SidebarGroup,
  SidebarGroupLabel,
  SidebarInset,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarProvider,
  SidebarTrigger,
} from "@cookest/ui";

Props

ExportProps typeNotes
SidebarProviderReact.ComponentProps<"div"> & { defaultOpen?: boolean; open?: boolean; onOpenChange?: (open: boolean) => void }Also wires the ⌘/Ctrl+b toggle shortcut
SidebarReact.ComponentProps<"div"> & { side?: "left" | "right"; variant?: "sidebar" | "floating" | "inset"; collapsible?: "offcanvas" | "icon" | "none" }Main sidebar surface
SidebarMenuButtonReact.ComponentProps<"button"> & { asChild?: boolean; isActive?: boolean; tooltip?: string | React.ComponentProps<typeof TooltipContent> }Primary menu action
SidebarMenuActionReact.ComponentProps<"button"> & { asChild?: boolean; showOnHover?: boolean }Secondary per-item action
SidebarGroupLabelReact.ComponentProps<"div"> & { asChild?: boolean }Group heading
SidebarMenuSubButtonReact.ComponentProps<"a"> & { asChild?: boolean; isActive?: boolean }Nested link button

Example

<SidebarProvider>
  <Sidebar>
    <SidebarContent>
      <SidebarGroup>
        <SidebarGroupLabel>Cookest</SidebarGroupLabel>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton isActive>Recipes</SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarGroup>
    </SidebarContent>
  </Sidebar>
  <SidebarInset>
    <SidebarTrigger />
  </SidebarInset>
</SidebarProvider>

Slider

Single-value slider with labels, marks, sizes, and color variants.

Import

import { Slider } from "@cookest/ui";

Props

PropTypeDefaultDescription
valuenumberβ€”Controlled value
defaultValuenumberβ€”Uncontrolled starting value
minnumber0Minimum value
maxnumber100Maximum value
stepnumber1Step size
labelstringβ€”Label above the control
showValuebooleanfalseShow current numeric value
disabledbooleanfalseDisable interaction
size"sm" | "md" | "lg""md"Track/thumb size
color"primary" | "success" | "warning" | "error""primary"Active track color
marksSliderMark[]β€”Tick labels { value, label? }
onChange(value: number) => voidβ€”Value change callback
classNamestringβ€”Wrapper classes

Example

<Slider
  min={0}
  max={60}
  value={minutes}
  onChange={setMinutes}
  showValue
  marks={[{ value: 15 }, { value: 30 }, { value: 45 }]}
/>

Sonner

Thin wrapper around sonner for app-wide toast notifications.

Import

import { SonnerToaster } from "@cookest/ui";

Props

ExportProps typeNotes
SonnerToasterReact.ComponentProps<typeof Sonner>Re-exported as SonnerToaster from @cookest/ui

Example

<>
  <SonnerToaster richColors closeButton />
</>

Spinner

Loading spinner with size, color, and accessible label support.

Import

import { Spinner } from "@cookest/ui";

Props

PropTypeDefaultDescription
size"xs" | "sm" | "md" | "lg" | "xl""md"Spinner size
color"primary" | "white" | "current""primary"Stroke color
labelstringβ€”Screen-reader label
classNamestringβ€”Additional classes

Example

<Spinner size="lg" label="Loading recipes" />

Switch

Binary on/off switch using Radix switch primitives.

Import

import { Switch } from "@cookest/ui";

Props

ExportProps typeNotes
SwitchReact.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>Supports checked, defaultChecked, onCheckedChange, and disabled

Example

<Switch checked={usePantry} onCheckedChange={setUsePantry} aria-label="Use pantry" />

Table

Composable table primitives with styled headers, rows, and captions.

Import

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@cookest/ui";

Props

ExportProps typeNotes
TableReact.HTMLAttributes<HTMLTableElement>Wrapped in an overflow container
TableHeaderReact.HTMLAttributes<HTMLTableSectionElement><thead> helper
TableBodyReact.HTMLAttributes<HTMLTableSectionElement><tbody> helper
TableFooterReact.HTMLAttributes<HTMLTableSectionElement><tfoot> helper
TableHeadReact.ThHTMLAttributes<HTMLTableCellElement>Header cell
TableCellReact.TdHTMLAttributes<HTMLTableCellElement>Data cell
TableCaptionReact.HTMLAttributes<HTMLTableCaptionElement>Caption text

Example

<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Ingredient</TableHead>
      <TableHead>Qty</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>Eggs</TableCell>
      <TableCell>4</TableCell>
    </TableRow>
  </TableBody>
</Table>

Tabs

Data-driven tabs component with underline, pill, and boxed variants.

Import

import { Tabs } from "@cookest/ui";

Props

PropTypeDefaultDescription
itemsTabItem[]requiredTab definitions to render
defaultTabstringβ€”Initially selected tab ID
valuestringβ€”Controlled tab ID
onChange(id: string) => voidβ€”Tab change callback
variant"underline" | "pills" | "boxed""underline"Visual style
size"sm" | "md" | "lg""md"Trigger sizing
fullWidthbooleanfalseStretch triggers to fill width
classNamestringβ€”Wrapper classes

TabItem has the shape { id, label, icon?, disabled?, badge?, content }.

Example

<Tabs
  items={[
    { id: "ingredients", label: "Ingredients", content: <p>List</p> },
    { id: "steps", label: "Steps", content: <p>Steps</p> },
  ]}
/>

Textarea

Multi-line text input with labels, helper/error text, character counts, and auto-resize.

Import

import { Textarea } from "@cookest/ui";

Props

PropTypeDefaultDescription
labelstringβ€”Label text above the field
helperTextstringβ€”Help text below the field
errorstringβ€”Error message below the field
maxLengthnumberβ€”Native maximum length
showCountbooleanfalseShow current character count
resize"none" | "vertical" | "horizontal" | "both""vertical"CSS resize behavior
autoResizebooleanfalseGrow the textarea with content
inputSize"sm" | "md" | "lg""md"Control sizing
fullWidthbooleanfalseStretch to container width
classNamestringβ€”Wrapper classes
...propsTextareaHTMLAttributes<HTMLTextAreaElement>β€”Native textarea props are forwarded

Example

<Textarea
  label="Notes"
  helperText="Add substitutions or serving tips"
  showCount
  maxLength={280}
  autoResize
/>

Toast

Low-level toast primitives plus an imperative toast store.

Import

import {
  Toast,
  ToastAction,
  ToastDescription,
  ToastTitle,
  Toaster,
  toast,
  useToast,
} from "@cookest/ui";

Props

ExportProps / return typeNotes
ToastReact.ComponentPropsWithoutRef<typeof Toast>Low-level toast primitive
ToastActionReact.ReactElement<typeof ToastAction>Optional inline action button
ToasternoneMount once near the app root
toast(options: Omit<ToasterToast, "id">) => { id, dismiss, update }Imperative helper from use-toast.ts
useToast() => { toasts, toast, dismiss }Hook exposing current toast state and helpers

Example

<>
  <Button
    onClick={() =>
      toast({
        title: "Saved",
        description: "Recipe updated successfully.",
      })
    }
  >
    Show toast
  </Button>
  <Toaster />
</>

ToggleGroup

Grouped toggle buttons for single or multiple selection.

Import

import { ToggleGroup, ToggleGroupItem } from "@cookest/ui";

Props

ExportProps typeNotes
ToggleGroupReact.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> & { size?: "sm" | "md" | "lg" }Group-level size defaults to "md"
ToggleGroupItemReact.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> & { size?: "sm" | "md" | "lg" }Item can override the inherited size

Example

<ToggleGroup type="single" value={view} onValueChange={setView}>
  <ToggleGroupItem value="list">List</ToggleGroupItem>
  <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
</ToggleGroup>

On this page