
Coss
- 3k installs
- 10.4k repo stars
- Updated August 4, 2026
- cosscom/coss
coss is a component skill for implementing coss UI primitives on Base UI with Tailwind v4, particles, and shadcn migration patterns.
About
The coss skill helps agents implement coss UI components built on Base UI with a shadcn-like developer experience and a large particle catalog. It routes tasks to the right primitives via a component registry, enforces documented trigger and content hierarchies for dialogs, menus, selects, and popovers, and prefers existing particles over inventing markup. Source of truth links point to coss component docs, particle examples, and llms.txt for agents. Critical rules forbid inventing APIs, require accessibility labels, guide manual install dependency lists, and prefer styled exports over Primitive variants unless custom composition demands them. Workflow steps identify intent, consult the registry, check particle examples like p-dialog-1.tsx, write minimal code, and self-check composition invariants. High-risk primitive guides cover dialog, menu, select, form, input-group, and toast with toastManager instead of Sonner. Installation uses npx shadcn@latest add @coss/component. Out of scope includes monorepo internals unless explicitly requested. Requires Tailwind CSS v4 and @base-ui/react.
- 54 primitives with dedicated reference guides and registry index.
- Trigger-based overlay composition rules per primitive type.
- Particle example workflow from apps/ui/registry particles catalog.
- shadcn and Radix to coss Base UI migration reference.
- High-risk primitive guides for dialog, menu, select, form, and toast.
Coss by the numbers
- 3,036 all-time installs (skills.sh)
- +122 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #181 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
coss capabilities & compatibility
- Capabilities
- component registry discovery across 54 primitive · documented trigger and popup composition enforce · particle example referencing for practical patte · shadcn and radix migration rule application · form, dialog, menu, select, and toast high risk · cli and manual install workflow guidance
- Use cases
- frontend · ui design · web design
- Pricing
- Free
What coss says it does
Do not invent coss APIs. Verify against component docs first.
High-risk primitives (read these guides first -- they have the most composition gotchas)
npx skills add https://github.com/cosscom/coss --skill cossAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3k |
|---|---|
| repo stars | ★ 10.4k |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 4, 2026 |
| Repository | cosscom/coss ↗ |
How do I write correct coss UI code without mixing Radix assumptions or inventing undocumented component APIs?
Implement coss UI primitives correctly with Base UI composition, Tailwind v4 styling, and shadcn migration patterns.
Who is it for?
React teams using coss with Tailwind v4 who need primitive selection, code examples, and migration guidance.
Skip if: Skip for non-React stacks, coss monorepo build pipeline maintenance, or backend API work without UI components.
When should I use this skill?
User builds UIs with coss buttons, dialogs, selects, forms, menus, tabs, toasts, or migrates from shadcn or Radix.
What you get
Valid coss imports, trigger-content composition, accessible examples aligned to docs and particle patterns.
- coss component JSX
- accessible overlay patterns
- migration notes
Files
coss ui
coss ui is a component library built on Base UI with a shadcn-like developer experience plus a large particle catalog.
What this skill is for
Use this skill to:
- pick the right coss primitive(s) for a UI task
- write correct coss usage code (imports, composition, props)
- avoid common migration mistakes from shadcn/Radix assumptions
- reference particle examples to produce practical, production-like patterns
Source of truth
- coss components docs:
apps/ui/content/docs/components/*.mdx https://github.com/cosscom/coss/tree/main/apps/ui/content/docs/components- coss particle examples:
apps/ui/registry/default/particles/p-*.tsx https://github.com/cosscom/coss/tree/main/apps/ui/registry/default/particles- coss particles catalog:
https://coss.com/ui/particles - docs map for agents:
https://coss.com/ui/llms.txt
Out of scope
- Maintaining coss monorepo internals/build pipelines.
- Editing registry internals unless explicitly requested.
Principles for agent output
1. Use existing primitives and particles first before inventing custom markup. 2. Prefer composition over custom behavior reimplementation. 3. Follow coss naming and APIs from docs exactly. 4. Keep examples accessible and production-realistic. 5. Prefer concise code that mirrors coss docs/particles conventions. 6. Assume Tailwind CSS v4 conventions in coss examples and setup guidance.
Critical usage rules
Always apply before returning coss code:
- Do not invent coss APIs. Verify against component docs first.
- For trigger-based primitives (Dialog, Menu, Select, Popover, Tooltip), follow each primitive's documented trigger/content hierarchy and composition API; do not mix patterns across components.
- Preserve accessibility labels and error semantics.
- Consult primitive-specific guides for component invariants and edge cases.
- For manual install guidance, include all required dependencies and local component files referenced by imports.
- Prefer styled coss exports first; use
*Primitiveexports only when custom composition/styling requires it.
Rule references (read on demand when the task touches these areas):
./references/rules/styling.md— Tailwind tokens, icon conventions, data-slot selectors./references/rules/forms.md— Field composition, validation, input patterns./references/rules/composition.md— Trigger/popup hierarchies, grouped controls./references/rules/migration.md— shadcn/Radix to coss/Base UI migration patterns./references/portal-props.md— optionalportalPropson composed popups and toast providers (keepMounted,container, which surfaces support it)
Component discovery
All 54 primitives have dedicated reference guides at ./references/primitives/<name>.md. To find the right one for a task, consult the component registry index:
./references/component-registry.md
Usage workflow
1. Identify user intent (single primitive, composed flow, form flow, overlay flow, feedback flow). 2. Consult references/component-registry.md to identify candidate primitives. 3. Select primitives from coss docs first; avoid custom fallback unless needed. 4. Check at least one particle example for practical composition patterns. Particle files live at apps/ui/registry/default/particles/p-<name>-<N>.tsx (e.g. p-dialog-1.tsx). 5. Write minimal code using documented imports/props. 6. Self-check accessibility and composition invariants.
Installation reference
See ./references/cli.md for full install/discovery workflow.
Quick CLI pattern:
npx shadcn@latest add @coss/<component>Quick manual pattern:
- install dependencies listed in the component docs page
- copy required component file(s)
- update imports to match the target app alias setup
Primitive Guidance
Every primitive has a reference guide at ./references/primitives/<name>.md with imports, minimal patterns, inline code examples, pitfalls, and particle references. Use the component registry to find the right file.
High-risk primitives (read these guides first -- they have the most composition gotchas):
./references/primitives/dialog.md— modal overlays, form-in-dialog, responsive dialog/drawer./references/primitives/menu.md— dropdown actions, checkbox/radio items, submenus./references/primitives/context-menu.md— right-click/long-press menus at the pointer./references/primitives/select.md— items-first pattern, multiple, object values, groups./references/primitives/form.md— Field composition, validation, submission./references/primitives/input-group.md— addons, DOM order invariant, textarea layouts./references/primitives/toast.md— toastManager (not Sonner), anchored toasts, providers
Output Checklist
Before returning code:
- imports and props match coss docs
- composition structure is valid for selected primitive(s)
- accessibility and explicit control types (
button,input, etc.) are present - migration-sensitive flows are verified (type/lint, keyboard/a11y behavior, and SSR-sensitive primitives like Select/Command)
coss CLI Reference (Focused)
Use this guide when installing, previewing, or discovering coss components via the shadcn CLI.
CLI Safety Rules
- Always use the project's package runner:
npx shadcn@latest ...pnpm dlx shadcn@latest ...bunx --bun shadcn@latest ...- Do not invent flags. Use only documented CLI flags.
Core Commands for coss Usage
Recommended bootstrap paths
# New projects (recommended — includes Inter + Geist Mono fonts + full theme)
npx shadcn@latest init @coss/style
# Existing projects - all primitives
npx shadcn@latest add @coss/ui
# Existing projects - full theme setup
npx shadcn@latest add @coss/style
# Existing projects - primitives + color tokens
npx shadcn@latest add @coss/ui @coss/colors-neutral@coss/style automatically installs @coss/fonts (Inter for --font-sans and --font-heading, Geist Mono for --font-mono), which configures all three font variables in layout.tsx. No manual font wiring needed.
add (primary)
shadcn add @coss/<component>Examples:
npx shadcn@latest add @coss/dialog
npx shadcn@latest add @coss/select
npx shadcn@latest add @coss/toastadd preview mode (recommended)
npx shadcn@latest add @coss/dialog --dry-run
npx shadcn@latest add @coss/dialog --diff
npx shadcn@latest add @coss/dialog --viewUse preview mode when:
- user asks what will change
- component might already exist locally
- you need to inspect output before writing files
Optional discovery helpers (use when available)
npx shadcn@latest search @coss -q "dialog"
npx shadcn@latest view @coss/dialog
npx shadcn@latest docs dialog
npx shadcn@latest info --jsonIf these are unsupported in the environment, use fallback sources below.
Discovery Fallback Matrix
Inside the coss repo (preferred)
apps/ui/registry/registry-particles.tshttps://github.com/cosscom/coss/blob/main/apps/ui/registry/registry-particles.tsapps/ui/registry.jsonhttps://github.com/cosscom/coss/blob/main/apps/ui/registry.jsonapps/ui/content/docs/components/*.mdxhttps://github.com/cosscom/coss/tree/main/apps/ui/content/docs/components
Outside the coss repo
- coss particles catalog:
https://coss.com/ui/particles - coss docs catalog:
https://coss.com/ui/
Manual Install Path
When users explicitly request manual setup:
1. Read the target component docs. 2. Install exactly the listed dependencies. 3. Copy all required files (including transitive local imports). 4. Adjust imports for target app aliases. 5. Validate the snippet against docs/particles patterns.
Important:
- CLI setup usually wires required theme tokens automatically.
- Manual setup must include required additional tokens (
destructive-foreground,info,success,warningfamilies) from coss styling docs when relevant.
Quick Output Checklist
Before returning CLI guidance:
1. runner and command are valid for the user's package manager 2. flags are documented and intentional 3. fallback source is provided if CLI discovery commands are unavailable 4. resulting usage guidance matches coss docs and particles patterns
coss Component Registry Index
Use this file to quickly identify the right coss primitive for a UI task. Each entry includes the component name, a one-line purpose, and the path to its reference guide (relative to the skill root apps/ui/skills/coss/).
For optional `portalProps` on composed *Popup components and toast providers (Base UI portal forwarding), see ./references/portal-props.md.
Overlays & Popups
- Dialog — Centered modal requiring user focus.
./references/primitives/dialog.md - AlertDialog — Destructive/critical confirmation modal.
./references/primitives/alert-dialog.md - Sheet — Side-panel overlay for settings/details.
./references/primitives/sheet.md - Drawer — Bottom/side drawer, often mobile-responsive.
./references/primitives/drawer.md - Popover — Anchored non-modal floating content.
./references/primitives/popover.md - Tooltip — Short hover/focus hint text.
./references/primitives/tooltip.md - PreviewCard — Hover-triggered rich entity preview.
./references/primitives/preview-card.md - Menu — Dropdown action list with groups/submenus.
./references/primitives/menu.md - ContextMenu — Right-click/long-press action menu at the pointer.
./references/primitives/context-menu.md - Command — Searchable command palette (not cmdk).
./references/primitives/command.md
Selection & Input
- Select — Single-choice from predefined list (no search).
./references/primitives/select.md - Combobox — Searchable selection with filtering.
./references/primitives/combobox.md - Autocomplete — Free-text with suggestions.
./references/primitives/autocomplete.md - Input — Single-line text entry.
./references/primitives/input.md - Textarea — Multi-line text entry.
./references/primitives/textarea.md - InputGroup — Input with addons (icons, buttons, badges).
./references/primitives/input-group.md - OTPField — One-time passcode segmented slots.
./references/primitives/otp-field.md - NumberField — Numeric entry with stepper controls.
./references/primitives/number-field.md - Slider — Continuous/ranged numeric control.
./references/primitives/slider.md - Calendar — Date picker / calendar views.
./references/primitives/calendar.md
Forms & Validation
- Form — Form validation/submission with Zod.
./references/primitives/form.md - Field — Label + description + error wiring.
./references/primitives/field.md - Fieldset — Grouped form controls with legend.
./references/primitives/fieldset.md - Label — Accessible label for controls.
./references/primitives/label.md
Toggle & Choice
- Checkbox — Single boolean toggle.
./references/primitives/checkbox.md - CheckboxGroup — Multiple-selection set.
./references/primitives/checkbox-group.md - RadioGroup — Mutually exclusive single choice.
./references/primitives/radio-group.md - Switch — Binary on/off preference toggle.
./references/primitives/switch.md - Toggle — Pressable two-state command button.
./references/primitives/toggle.md - ToggleGroup — Grouped pressed-state controls.
./references/primitives/toggle-group.md
Layout & Navigation
- Tabs — Mutually exclusive tabbed panels.
./references/primitives/tabs.md - Accordion — Collapsible content sections.
./references/primitives/accordion.md - Collapsible — Single expand/collapse region.
./references/primitives/collapsible.md - Sidebar — Persistent app shell navigation.
./references/primitives/sidebar.md - Breadcrumb — Hierarchical navigation trail.
./references/primitives/breadcrumb.md - Pagination — Paged navigation controls.
./references/primitives/pagination.md - Toolbar — Grouped command/action strip.
./references/primitives/toolbar.md - ScrollArea — Styled scroll container.
./references/primitives/scroll-area.md
Content & Display
- Card — Content container with sections.
./references/primitives/card.md - Frame — Bordered content surface.
./references/primitives/frame.md - Table — Tabular data presentation.
./references/primitives/table.md - Avatar — User/entity profile image.
./references/primitives/avatar.md - Badge — Status indicator / label.
./references/primitives/badge.md - Kbd — Keyboard shortcut hints.
./references/primitives/kbd.md - Separator — Visual/semantic divider.
./references/primitives/separator.md - Group — Connected control cluster.
./references/primitives/group.md - Empty — Empty-state placeholder.
./references/primitives/empty.md
Feedback & Status
- Alert — Inline persistent status message.
./references/primitives/alert.md - Toast — Transient notification (toastManager).
./references/primitives/toast.md - Progress — Task completion / async progress bar.
./references/primitives/progress.md - Meter — Bounded scalar measurement.
./references/primitives/meter.md - Spinner — Indeterminate loading indicator.
./references/primitives/spinner.md - Skeleton — Loading placeholder.
./references/primitives/skeleton.md
Actions
- Button — Primary/secondary action trigger.
./references/primitives/button.md
Portal forwarding (portalProps)
Several composed coss primitives wrap Base UI `Portal` inside *Popup (or dialog-style) components, and toast exposes the same for `ToastProvider` / `AnchoredToastProvider`. Those surfaces accept an optional `portalProps` object, which is spread onto the internal Portal.
Use it when you need portal-level behavior from Base UI, for example:
- `keepMounted` — where the component’s
Portaltype supports it (see Base UI typings/docs for that component). - `container` — render portaled content into a specific DOM node (stacking contexts, micro-frontends, shadow DOM setups).
- Other props accepted by that component’s `Portal.Props` (including
className/refwhen applicable).
Surfaces that expose portalProps
- Modals / overlays:
DialogPopup,AlertDialogPopup,SheetPopup,DrawerPopup,CommandDialogPopup - Floating layers:
MenuPopup,ContextMenuPopup,PopoverPopup,TooltipPopup,PreviewCardPopup,AutocompletePopup,ComboboxPopup,SelectPopup - *Toast (providers, not a `Popup
name):**ToastProvider,AnchoredToastProvider—portalPropsis forwarded to the internalToast.Portal` for the stacked and anchored viewports, respectively
Only these surfaces accept portalProps. Any other registry component that portals content but is not listed here keeps the portal internal and is out of scope for this prop—compose Base UI parts yourself if you need direct portal control.
Positioner vs portal
portalProps only affects the portal node. To tweak placement or positioner styling, use the existing side, align, sideOffset, etc., or compose Base UI `Positioner` / pass through future `positionerProps` if the wrapper adds them.
coss Accordion
When to use
- Expandable multi-section content regions.
- FAQs and settings pages with progressive disclosure.
Install
npx shadcn@latest add @coss/accordionManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Accordion,
AccordionItem,
AccordionPanel,
AccordionTrigger,
} from "@/components/ui/accordion"Minimal pattern
<Accordion defaultValue={["item-1"]}>
<AccordionItem value="item-1">
<AccordionTrigger>What is Base UI?</AccordionTrigger>
<AccordionPanel>
Base UI is a library of high-quality unstyled React components.
</AccordionPanel>
</AccordionItem>
</Accordion>Patterns from coss particles
Key patterns
Multiple panels open simultaneously:
<Accordion multiple defaultValue={["item-1", "item-2"]}>
<AccordionItem value="item-1">
<AccordionTrigger>Section 1</AccordionTrigger>
<AccordionPanel>Content 1</AccordionPanel>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Section 2</AccordionTrigger>
<AccordionPanel>Content 2</AccordionPanel>
</AccordionItem>
</Accordion>Controlled mode with external state:
const [value, setValue] = useState<string[]>(["item-1"])
<Accordion value={value} onValueChange={setValue}>
...
</Accordion>Each AccordionItem needs a stable value; trigger and panel must be children of the same item.
More examples
See p-accordion-1 through p-accordion-4 for mapped items, single-open, multiple-open, and controlled patterns.
Common pitfalls
- Placing
AccordionTrigger/AccordionPaneloutsideAccordionItem. - Omitting
valueonAccordionItem, which breaks item identity and controlled behavior. - Applying Radix mental models like
type="single" | "multiple"instead of cossmultiple+ array values. - Treating controlled
valueas scalar instead ofstring[].
Useful particle references
- baseline mapped-items accordion:
p-accordion-1 - single-open static sections:
p-accordion-2 - multiple-open behavior:
p-accordion-3 - controlled value + external actions:
p-accordion-4
coss Alert Dialog
When to use
- Critical confirmation flows before destructive actions.
- Blocking decisions that require explicit acknowledgement.
When NOT to use
- If the content is informational (no destructive action) -> use Dialog instead.
- If the message is transient feedback -> use Toast instead.
- If the content is contextual and non-blocking -> use Popover instead.
Install
npx shadcn@latest add @coss/alert-dialogManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
AlertDialog,
AlertDialogClose,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogPopup,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"Minimal pattern
<AlertDialog>
<AlertDialogTrigger render={<Button variant="destructive-outline" />}>
Delete Account
</AlertDialogTrigger>
<AlertDialogPopup>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>Cancel</AlertDialogClose>
<AlertDialogClose render={<Button variant="destructive" />}>
Delete Account
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogPopup>
</AlertDialog>Patterns from coss particles
- Portal forwarding: optional
portalPropsonAlertDialogPopup→ Base UIAlertDialog.Portal(keepMounted,container, …). See portal-props.md. - Section structure: keep
AlertDialogHeaderandAlertDialogFooteras direct sections ofAlertDialogPopup(there is noAlertDialogPanel; add adivor fragment between them only if you need extra body content). - Action composition: use
AlertDialogClose render={<Button ... />}for cancel/confirm actions to preserve button semantics and styling. - Destructive affordance: pair destructive trigger/confirm variants (
destructive-outline,destructive) for clear risk signaling. - Footer variants: use
AlertDialogFooter variant="bare"when border/background framing should be removed. - Close confirmation chain: for unsaved changes in broader workflows, pair with dialog flows like
p-dialog-4.
Common pitfalls
- Using AlertDialog as a generic content modal instead of high-risk confirmation UI.
- Omitting explicit destructive/cancel action distinction.
- Wrapping dialog sections in extra containers that break built-in layout (use
className="contents"only when needed). - Mixing Dialog/Popover composition APIs without validating this primitive's parts.
- Skipping focus-return and escape-key verification on real trigger flows.
Useful particle references
- core alert-dialog patterns:
p-alert-dialog-1,p-alert-dialog-2 - related close-confirmation flow:
p-dialog-4
coss Alert
When to use
- Inline status messaging in content flows.
- Semantic feedback variants (
info,success,warning,error) with optional icons and actions.
When NOT to use
- If the message is transient and should auto-dismiss -> use Toast instead.
- If the message requires user action before proceeding -> use AlertDialog instead.
- If it's a brief hover hint -> use Tooltip instead.
Install
npx shadcn@latest add @coss/alertManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import { Alert, AlertAction, AlertDescription, AlertTitle } from "@/components/ui/alert"Minimal pattern
<Alert>
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components and dependencies to your app using the cli.
</AlertDescription>
</Alert>Patterns from coss particles
Key patterns
Alert with semantic icon (do NOT use aria-hidden — icon conveys status):
<Alert variant="info">
<InfoIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>You can add components using the CLI.</AlertDescription>
</Alert>Variants: default, info, success, warning, error.
Alert with action buttons (use AlertAction):
<Alert>
<InfoIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>Describe what can be done about it here.</AlertDescription>
<AlertAction>
<Button size="xs" variant="ghost">Dismiss</Button>
<Button size="xs">Ok</Button>
</AlertAction>
</Alert>More examples
See p-alert-1 through p-alert-7 for all variants and action patterns.
Common pitfalls
- Using alert variants for passive decoration instead of meaningful semantic status.
- Missing title/description structure in complex alerts, reducing scannability.
- Hiding semantic alert icons with
aria-hiddenwhen they convey status meaning.
Useful particle references
- with icon:
p-alert-2 - with icon and action buttons:
p-alert-3 - info alert:
p-alert-4 - success alert:
p-alert-5 - warning alert:
p-alert-6 - error alert:
p-alert-7
coss Autocomplete
When to use
- Search-driven suggestion pickers with free typing.
- Assisted text entry over a known option space with keyboard navigation.
When NOT to use
- If options are predefined and don't need search -> use Select instead.
- If the user must pick from a strict set (no free text) -> use Combobox instead.
- If you need action commands, not data selection -> use Command instead.
Install
npx shadcn@latest add @coss/autocompleteManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Autocomplete,
AutocompleteCollection,
AutocompleteEmpty,
AutocompleteGroup,
AutocompleteGroupLabel,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
AutocompleteSeparator,
AutocompleteStatus,
useAutocompleteFilter,
} from "@/components/ui/autocomplete"Minimal pattern
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
]
<Autocomplete items={items}>
<AutocompleteInput aria-label="Search items" placeholder="Search items…" />
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>For form-bound autocomplete controls, prefer Field wrappers so label, required state, and error output remain tied to the same control.
Patterns from coss particles
- Portal forwarding: optional
portalPropsonAutocompletePopup→ Base UI combobox/autocomplete portal (keepMounted,container, …). See portal-props.md.
Key patterns
Autocomplete with input affordances:
<Autocomplete items={items}>
<AutocompleteInput
aria-label="Search frameworks"
placeholder="Search..."
showClear
showTrigger
startAddon={<SearchIcon aria-hidden="true" />}
/>
<AutocompletePopup>
<AutocompleteEmpty>No results found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => <AutocompleteItem key={item.value} value={item}>{item.label}</AutocompleteItem>}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>Grouped lists:
<AutocompleteList>
<AutocompleteGroup>
<AutocompleteGroupLabel>Fruits</AutocompleteGroupLabel>
<AutocompleteCollection>
{(item) => <AutocompleteItem key={item.value} value={item}>{item.label}</AutocompleteItem>}
</AutocompleteCollection>
</AutocompleteGroup>
</AutocompleteList>Async search: use filter={null}, control value/onValueChange, and provide itemToStringValue for object results.
Form integration: place Autocomplete inside Field name="..." with FieldLabel/FieldError.
More examples
See p-autocomplete-1 through p-autocomplete-15 for sizes, matching behavior, groups, limited results, async, form integration, and pill input patterns.
Common pitfalls
- Omitting
AutocompleteEmpty, leaving blank popups with no user feedback. - Using object items in async/custom flows without
itemToStringValue, which breaks stable string mapping. - Mixing combobox/select assumptions into autocomplete APIs without checking docs.
- Missing explicit labels (
FieldLabeloraria-label) on the input. - Not handling async race/error states (
loading,error, stale response cancellation).
Useful particle references
- baseline + size + disabled:
p-autocomplete-1,p-autocomplete-2,p-autocomplete-3,p-autocomplete-4 - label + input affordances (
showClear,showTrigger,startAddon):p-autocomplete-5,p-autocomplete-8,p-autocomplete-9,p-autocomplete-14 - matching behavior (
mode="both",autoHighlight):p-autocomplete-6,p-autocomplete-7 - grouped options:
p-autocomplete-10 - limited results with status message:
p-autocomplete-11 - async search with loading/error status:
p-autocomplete-12 - form integration:
p-autocomplete-13 - style variant (pill input):
p-autocomplete-15
coss Avatar
When to use
- Identity visuals for users/teams in compact spaces.
- Image + fallback initials patterns in cards, lists, and menus.
Install
npx shadcn@latest add @coss/avatarManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"Minimal pattern
<Avatar>
<AvatarImage src="/avatars/01.png" alt="User avatar" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>Patterns from coss particles
Key patterns
Custom size via Tailwind class:
<Avatar className="size-16">
<AvatarImage src="/avatar.png" alt="User avatar" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>Stacked avatar group:
<div className="flex -space-x-3">
<Avatar className="ring-2 ring-background">
<AvatarImage src="/user-1.png" alt="User 1" />
<AvatarFallback>U1</AvatarFallback>
</Avatar>
<Avatar className="ring-2 ring-background">
<AvatarImage src="/user-2.png" alt="User 2" />
<AvatarFallback>U2</AvatarFallback>
</Avatar>
</div>More examples
See p-avatar-1 through p-avatar-5 for sizes, radii, fallback-only, and group patterns.
Common pitfalls
- Omitting
AvatarFallback, causing broken image states with no identity fallback. - Using non-descriptive
alttext onAvatarImagein accessible contexts. - Relying on oversized custom wrappers instead of built-in size variants/classes.
Useful particle references
- fallback only:
p-avatar-2 - different sizes:
p-avatar-3 - different radius:
p-avatar-4 - group avatars:
p-avatar-5
coss Badge
When to use
- Short status/category labels and counts.
- Inline metadata chips paired with buttons, tables, and cards.
Install
npx shadcn@latest add @coss/badgeManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Badge } from "@/components/ui/badge"Minimal pattern
<Badge>Badge</Badge>Patterns from coss particles
Key patterns
Variants via the variant prop:
<Badge>Default</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="info">Info</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="error">Error</Badge>Badge with decorative icon:
<Badge variant="outline">
<CheckIcon aria-hidden="true" />
Verified
</Badge>Badge inside a button (use negative margin for alignment):
<Button variant="outline">
Messages
<Badge className="-me-1" variant="outline">18</Badge>
</Button>More examples
See p-badge-1 through p-badge-9 for all variant/size combinations.
Common pitfalls
- Using badge as interactive button without proper button semantics.
- Applying raw palette classes instead of semantic tokens/variants for status.
- Overloading badge content with long text that should be normal body copy.
Useful particle references
See p-badge-1 through p-badge-9 for all variants (outline, secondary, destructive, info, success, warning, error, small).
coss Breadcrumb
When to use
- Hierarchy/location indicators for current page context.
- Compact navigation trails for nested routes and detail pages.
Install
npx shadcn@latest add @coss/breadcrumbManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"Minimal pattern
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbEllipsis />
</BreadcrumbItem>
<BreadcrumbItem>
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>Patterns from coss particles
Key patterns
Icon-only home link (requires aria-label):
<BreadcrumbItem>
<BreadcrumbLink aria-label="Home" href="/">
<HomeIcon aria-hidden="true" className="size-4" />
</BreadcrumbLink>
</BreadcrumbItem>Custom separator:
<BreadcrumbSeparator>
<SlashIcon className="size-3.5" />
</BreadcrumbSeparator>More examples
See p-breadcrumb-1 and p-breadcrumb-2 for default and custom separator patterns.
Common pitfalls
- Using breadcrumb as primary nav menu instead of contextual trail.
- Omitting
aria-labelon icon-only breadcrumb items. - Adding deep breadcrumb chains without meaningful hierarchy.
Useful particle references
- with custom separator:
p-breadcrumb-2
coss Button
When to use
- Primary and secondary action triggers.
- Icon, loading, and shortcut-enhanced actions across forms and toolbars.
Install
npx shadcn@latest add @coss/buttonManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Button } from "@/components/ui/button"Minimal pattern
<Button type="button">Button</Button>Button defaults to type="button" when rendered as the native button part. In form flows, set type explicitly (button / submit / reset) to match intent, especially when using render composition.
Patterns from coss particles
Key patterns
Variants are set via the variant prop:
<Button>Default</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>Icon-only button (always needs aria-label):
<Button aria-label="Close" size="icon" variant="ghost">
<XIcon aria-hidden="true" />
</Button>Button with icon and text (no opacity on the icon):
<Button>
<PlusIcon aria-hidden="true" />
Add Item
</Button>Sizes: xs, sm, default, lg, icon-xs, icon-sm, icon, icon-lg.
Loading state
Built-in loading prop (disables and shows spinner automatically):
<Button loading={isLoading} onClick={handleClick}>Submit</Button>Composite approach (manual Spinner + disabled):
<Button disabled>
<Spinner />
Loading...
</Button>Prefer the loading prop for typical async actions. Use the composite approach when you need custom spinner placement or label.
More examples
- default:
p-button-1 - outline:
p-button-2 - secondary:
p-button-3 - destructive:
p-button-4 - destructive outline:
p-button-5 - ghost:
p-button-6 - link:
p-button-7 - extra-small size:
p-button-8
Common pitfalls
- Omitting explicit
typeinside forms/dialogs and triggering unintended submit behavior. - Using icon-only buttons without
aria-labelon the button. - Rebuilding button state styling with ad-hoc classes instead of variants/sizes.
- Using
SelectButtonas if it were a general-purposeButton;SelectButtonis a select-flavored trigger helper and should be treated as aselect/comboboxpattern.
Useful particle references
- variants/sizes:
p-button-1throughp-button-8 - composite loading (Spinner + disabled):
p-button-18 - built-in loading prop:
p-button-41
coss Calendar
When to use
- Date selection interfaces and calendar-based scheduling UIs.
- Single-date, range, and constrained date picking patterns.
Install
npx shadcn@latest add @coss/calendarManual deps from docs:
npm install react-day-pickerCanonical imports
import { Calendar } from "@/components/ui/calendar"Minimal pattern
<Calendar mode="single" />Patterns from coss particles
Key patterns
Single date selection with state:
const [date, setDate] = useState<Date | undefined>()
<Calendar mode="single" selected={date} onSelect={setDate} />Date range selection:
const [range, setRange] = useState<DateRange | undefined>()
<Calendar mode="range" selected={range} onSelect={setRange} />More examples
See p-calendar-1 through p-calendar-6 for single, range, dropdown navigation, and month/year select patterns.
Common pitfalls
- Using calendar for free-text date input flows better handled by date fields.
- Missing locale/disabled-date constraints for business rules.
- Treating calendar as date-time picker without explicit time UI.
Useful particle references
- single date selection:
p-calendar-2 - date range selection:
p-calendar-3 - dropdown navigation:
p-calendar-4 - select dropdown for month/year:
p-calendar-5 - combobox dropdown for month/year:
p-calendar-6
coss Card
When to use
- Structured surface sections for grouped content.
- Settings, dashboard, and preview layouts with header/panel/footer semantics.
Install
npx shadcn@latest add @coss/cardManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import {
Card,
CardDescription,
CardFooter,
CardHeader,
CardPanel,
CardTitle,
} from "@/components/ui/card"Minimal pattern
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Description</CardDescription>
</CardHeader>
<CardPanel>Content</CardPanel>
<CardFooter>Footer</CardFooter>
</Card>Patterns from coss particles
Key patterns
Card with form content:
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>Deploy your new project in one click.</CardDescription>
</CardHeader>
<CardPanel className="flex flex-col gap-4">
<Field>
<FieldLabel>Name</FieldLabel>
<Input type="text" placeholder="My project" />
</Field>
</CardPanel>
<CardFooter className="flex justify-end gap-2">
<Button variant="ghost">Cancel</Button>
<Button>Create</Button>
</CardFooter>
</Card>Keep CardHeader, CardPanel, and CardFooter as direct children of Card to preserve built-in spacing and layout.
More examples
See p-card-1 through p-card-8 for various card compositions.
Common pitfalls
- Skipping
CardHeader/CardPanel/CardFooterstructure in composed cards. - Mixing unrelated layout wrappers that break spacing between card sections.
- Using cards as generic wrappers when
Frameor plain layout would be clearer.
Useful particle references
- core patterns:
p-card-1,p-card-2,p-card-3,p-card-4,p-card-5,p-card-6,p-card-7,p-card-8
coss Checkbox Group
When to use
- Multi-select option groups with shared label context.
- Collecting multiple values under one field name.
Install
npx shadcn@latest add @coss/checkbox-groupManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Checkbox } from "@/components/ui/checkbox"
import { CheckboxGroup } from "@/components/ui/checkbox-group"Minimal pattern
<CheckboxGroup>
<Label>
<Checkbox defaultChecked />
Next.js
</Label>
<Label>
<Checkbox />
Vite
</Label>
<Label>
<Checkbox />
Astro
</Label>
</CheckboxGroup>For form-bound option groups, prefer Field + Fieldset composition so legend, labels, and errors are grouped correctly.
Patterns from coss particles
Key patterns
Group with aria-label and defaultValue:
<CheckboxGroup aria-label="Select frameworks" defaultValue={["next"]}>
<Label>
<Checkbox value="next" />
Next.js
</Label>
<Label>
<Checkbox value="vite" />
Vite
</Label>
</CheckboxGroup>Controlled group:
const [value, setValue] = useState(["next"])
<CheckboxGroup value={value} onValueChange={setValue}>
...
</CheckboxGroup>For form-bound groups, use Field + Fieldset so legend, labels, and errors are grouped correctly.
More examples
See p-checkbox-group-1 through p-checkbox-group-5 for disabled items, parent checkbox, nested, and form patterns.
Common pitfalls
- Using checkbox group when only one option should be selected.
- Missing group label/legend context for assistive technology.
- Incorrectly handling submitted values as scalar instead of array/list.
Useful particle references
- with disabled item:
p-checkbox-group-2 - parent checkbox:
p-checkbox-group-3 - nested parent checkbox:
p-checkbox-group-4 - form integration:
p-checkbox-group-5 - form composition references:
p-form-1,p-form-2,p-input-group-24
coss Checkbox
When to use
- Single boolean consent/selection controls.
- Standalone yes/no options with explicit labeling.
When NOT to use
- If the control is a preference toggle (on/off) in settings -> use Switch instead.
- If selecting from mutually exclusive options -> use RadioGroup instead.
- If multiple checkboxes share grouped state -> use CheckboxGroup instead.
Install
npx shadcn@latest add @coss/checkboxManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Checkbox } from "@/components/ui/checkbox"Minimal pattern
<Label>
<Checkbox value="terms" />
Accept terms and conditions
</Label>Patterns from coss particles
Key patterns
CheckboxGroup with label-wrapped options:
<CheckboxGroup aria-label="Select frameworks" defaultValue={["next"]}>
<Label>
<Checkbox value="next" />
Next.js
</Label>
<Label>
<Checkbox value="vite" />
Vite
</Label>
<Label>
<Checkbox value="astro" />
Astro
</Label>
</CheckboxGroup>Checkbox with description text (use id/htmlFor):
const id = useId()
<div className="flex items-start gap-2">
<Checkbox id={id} />
<div className="flex flex-col gap-1">
<Label htmlFor={id}>Accept terms and conditions</Label>
<p className="text-muted-foreground text-xs">
By clicking this checkbox, you agree to the terms.
</p>
</div>
</div>More examples
- disabled:
p-checkbox-2 - with description:
p-checkbox-3 - card style:
p-checkbox-4 - form integration:
p-checkbox-5
Common pitfalls
- Using checkbox for exclusive single-choice options that should be radios.
- Missing visible label association (
LabelorFieldLabel) for each checkbox. - Treating
onCheckedChangevalues as plain boolean without handling indeterminate where relevant.
Useful particle references
See p-checkbox-1 through p-checkbox-5 for label wrapping, disabled, description, card, and form patterns.
coss Collapsible
When to use
- Progressive disclosure of optional content.
- Expandable help/settings sections without leaving the page.
Install
npx shadcn@latest add @coss/collapsibleManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
} from "@/components/ui/collapsible"Minimal pattern
<Collapsible>
<CollapsibleTrigger>Can I access the file in the cloud?</CollapsibleTrigger>
<CollapsiblePanel>
Yes, you can access the file in the cloud.
</CollapsiblePanel>
</Collapsible>Patterns from coss particles
Key patterns
Controlled collapsible:
const [open, setOpen] = useState(false)
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleTrigger>
{open ? "Hide details" : "Show details"}
</CollapsibleTrigger>
<CollapsiblePanel>Hidden content here.</CollapsiblePanel>
</Collapsible>More examples
See p-collapsible-1 for the core pattern.
Common pitfalls
- Placing trigger/panel outside the same collapsible root.
- Assuming panel content is always visible/mounted for dependent logic.
- Using modal-like interactions where collapsible disclosure is more appropriate.
Useful particle references
- core patterns:
p-collapsible-1
coss Combobox
When to use
- Searchable selection combining text input and list selection.
- Rich option rows with filtering and custom trigger behavior.
When NOT to use
- If options are few and fixed (no search needed) -> use Select instead.
- If you need free-form text suggestions without strict selection -> use Autocomplete instead.
- If the user picks from a simple short list -> use RadioGroup or Select.
Install
npx shadcn@latest add @coss/comboboxManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Combobox,
ComboboxClear,
ComboboxCollection,
ComboboxEmpty,
ComboboxGroup,
ComboboxGroupLabel,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxSeparator,
ComboboxValue,
useComboboxFilter,
} from "@/components/ui/combobox"Minimal pattern
const items = [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "orange", label: "Orange" },
{ value: "grape", label: "Grape" },
]
<Combobox items={items}>
<ComboboxInput placeholder="Select an item..." />
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => <ComboboxItem key={item.value} value={item}>{item.label}</ComboboxItem>}
</ComboboxList>
</ComboboxPopup>
</Combobox>For form-bound comboboxes, prefer Field composition (Field + FieldLabel + FieldError) instead of standalone controls.
Patterns from coss particles
- Portal forwarding: optional
portalPropsonComboboxPopup→ Base UICombobox.Portal(keepMounted,container, …). See portal-props.md.
Key patterns
Combobox with label in a Field:
<Field>
<FieldLabel>Framework</FieldLabel>
<Combobox items={items}>
<ComboboxInput placeholder="Search..." />
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => <ComboboxItem key={item.value} value={item}>{item.label}</ComboboxItem>}
</ComboboxList>
</ComboboxPopup>
</Combobox>
</Field>Sizes: sm, default, lg on ComboboxInput.
More examples
See p-combobox-1 through p-combobox-9 for sizes, label, auto-highlight, clear button, groups, and multiple selection.
Common pitfalls
- Mixing select and combobox APIs without validating item/value wiring.
- Using object values without stable string serialization where needed.
- Missing empty/loading states for remote or filtered datasets.
Useful particle references
- disabled:
p-combobox-2 - small size:
p-combobox-3 - large size:
p-combobox-4 - with label:
p-combobox-5 - auto highlight:
p-combobox-6 - with clear button:
p-combobox-7 - with groups:
p-combobox-8 - with multiple selection:
p-combobox-9 - related search/selection references:
p-autocomplete-1,p-select-1,p-input-group-1
coss Command
When to use
- Command palette and keyboard-navigable action menus.
- Fast action discovery for power-user and app shortcut workflows.
When NOT to use
- If the list is a simple set of actions without search -> use Menu instead.
- If the user is selecting from a predefined list -> use Select or Combobox instead.
- If the flow is a data form -> use Form instead.
Install
npx shadcn@latest add @coss/commandManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Command,
CommandCollection,
CommandDialog,
CommandDialogPopup,
CommandDialogTrigger,
CommandEmpty,
CommandFooter,
CommandGroup,
CommandGroupLabel,
CommandInput,
CommandItem,
CommandList,
CommandPanel,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command"
import { Button } from "@/components/ui/button"Minimal pattern
const items = [
{ value: "linear", label: "Linear" },
{ value: "figma", label: "Figma" },
{ value: "slack", label: "Slack" },
]
<CommandDialog>
<CommandDialogTrigger render={<Button variant="outline" />}>
Open Command Palette
</CommandDialogTrigger>
<CommandDialogPopup>
<Command items={items}>
<CommandInput placeholder="Search..." />
<CommandEmpty>No results found.</CommandEmpty>
<CommandList>
{(item) => (
<CommandItem key={item.value} value={item.value}>
{item.label}
</CommandItem>
)}
</CommandList>
</Command>
</CommandDialogPopup>
</CommandDialog>Patterns from coss particles
- Portal forwarding: optional
portalPropsonCommandDialogPopup→ Base UIDialog.Portal(keepMounted,container, …). See portal-props.md.
Key patterns
Command with grouped sections:
<Command items={items}>
<CommandInput placeholder="Type a command..." />
<CommandEmpty>No results found.</CommandEmpty>
<CommandList>
<CommandGroup>
<CommandGroupLabel>Suggestions</CommandGroupLabel>
<CommandCollection>
{(item) => (
<CommandItem key={item.value} value={item.value}>
{item.label}
</CommandItem>
)}
</CommandCollection>
</CommandGroup>
</CommandList>
</Command>Use CommandDialog + CommandDialogTrigger + CommandDialogPopup to wrap Command in a dialog overlay. Use controlled open/onOpenChange state for keyboard-shortcut activation.
More examples
See p-command-1 and p-command-2 for dialog palette and grouped action patterns.
Common pitfalls
- Using command list without clear grouping and action labels.
- Binding critical destructive actions without confirmation pathway.
- Missing keyboard accessibility checks for arrow/select/escape interactions.
Useful particle references
- core patterns:
p-command-1,p-command-2 - related search/selection references:
p-autocomplete-1,p-select-1,p-input-group-1
coss Context Menu
When to use
- Right-click or long-press action menus anchored to the pointer.
- Surface-specific actions on cards, rows, canvases, or media.
- The same action sets you might also expose in a dropdown
Menu.
When NOT to use
- If the user needs a click-to-open trigger button -> use Menu instead.
- If the user needs to search/filter actions -> use Command instead.
- If the content is rich informational (not actions) -> use Popover instead.
Install
npx shadcn@latest add @coss/context-menuManual deps and theme var from docs:
npm install @base-ui/reactAlso include the destructive foreground CSS variable snippet from the coss context menu docs when doing manual setup.
Canonical imports
import {
ContextMenu,
ContextMenuCheckboxItem,
ContextMenuGroup,
ContextMenuGroupLabel,
ContextMenuItem,
ContextMenuLinkItem,
ContextMenuPopup,
ContextMenuRadioGroup,
ContextMenuRadioItem,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuSub,
ContextMenuSubPopup,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from "@/components/ui/context-menu"Minimal pattern
<ContextMenu>
<ContextMenuTrigger className="flex h-32 items-center justify-center rounded-lg border border-dashed">
Right click here
</ContextMenuTrigger>
<ContextMenuPopup>
<ContextMenuItem>Back</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem>Reload</ContextMenuItem>
</ContextMenuPopup>
</ContextMenu>Wrap the trigger around the surface that should accept right click or long press. The popup opens at the pointer automatically.
Patterns from coss particles
- Portal forwarding: optional
portalPropsonContextMenuPopup-> Base UIContextMenu.Portal(keepMounted,container, ...). See portal-props.md. - Use
ContextMenuTriggeron a non-interactive wrapper (div) around the target surface. - Use
ContextMenuLinkItemfor navigation links. - If you were on
ContextMenuItem render={<Link href="..." />}, switch toContextMenuLinkItembut keep `render={<Link … />}` — do not usehrefalone with a router Link. - Use
hrefonContextMenuLinkItemonly for plain<a>navigation. - Use
ContextMenuItem closeOnClickfor action items that should dismiss the menu. - Use
ContextMenuCheckboxItem variant="switch"for toggle-style preferences. - Use
ContextMenuRadioGroup+ContextMenuRadioItemfor single-choice options. - Use
variant="destructive"on dangerous actions. - Use
ContextMenuSub+ContextMenuSubTrigger+ContextMenuSubPopupfor nested menus.
Common pitfalls
- Putting interactive controls inside
ContextMenuTriggerwithout careful event handling. - Forgetting
ContextMenuSubPopupfor nested menus. - Mixing navigation and action items without clear close behavior (
closeOnClick).
Useful particle references
- basic pointer menu:
p-context-menu-1 - link/navigation with
ContextMenuLinkItem render={<Link … />}:p-context-menu-2 - nested submenu pattern:
p-context-menu-3 - checkbox item pattern:
p-context-menu-4 - grouped sections with labels:
p-context-menu-5 - icons, shortcuts, and destructive actions:
p-context-menu-6 - radio group pattern:
p-context-menu-7 - switch-style checkbox items:
p-context-menu-8
Related primitives
- dropdown click menu: menu.md
- mobile action sheet variant: drawer.md
coss Dialog
When to use
- Modal overlays that require user focus and explicit action.
- Multi-section popup flows with header/body/footer structure.
When NOT to use
- If the overlay should slide from the edge -> use Sheet or Drawer instead.
- If the interaction is a destructive confirmation -> use AlertDialog instead.
- If the content is non-blocking contextual info -> use Popover instead.
Install
npx shadcn@latest add @coss/dialogManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"Minimal pattern
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>Open Dialog</DialogTrigger>
<DialogPopup>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Description</DialogDescription>
</DialogHeader>
<DialogPanel>Content</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>Close</DialogClose>
</DialogFooter>
</DialogPopup>
</Dialog>Patterns from coss particles
- Portal forwarding: optional
portalPropsonDialogPopup→ Base UIDialog.Portal(keepMounted,container, …). See portal-props.md. - Section structure invariant: keep
DialogHeader,DialogPanel, andDialogFooteras direct sections inDialogPopupto preserve built-in layout/styling behavior. - Form in dialog: keep `DialogHeader` outside the form; wrap `DialogPanel` + `DialogFooter` in `<Form className="contents">` (or native
<form className="contents">) so the popup’s flex column treats header, panel, and footer as direct layout sections. - Action buttons: use
DialogClosewithrender={<Button ... />}for cancel/close actions and set explicittypeon submit/action buttons. - Scrollable content: keep long content inside
DialogPanelto preserve dialog scroll behavior. - Footer variants: use
DialogFooter variant="bare"when border/background framing should be removed. - Controlled open state: for cross-component flows (for example menu item opens dialog), control with
open+onOpenChange. - Detached trigger option (advanced): when the opener cannot live in the same subtree, use a detached/external trigger pattern via controlled state (
open+onOpenChange) instead of forcing localDialogTriggercomposition. - Close confirmation flow: when unsaved changes exist, combine controlled
DialogwithAlertDialogconfirmation before closing. - Nested dialogs: supported; use clear trigger hierarchy and consider disabling default close buttons with
showCloseButton={false}when custom actions are preferred. - Responsive dialog/drawer variant: for form-heavy overlays, use
Dialogon desktop and switch toDraweron mobile (useMediaQuery("max-md")), keeping the sameFormstructure in both.
Common pitfalls
- Omitting
render={<Button ... />}composition on trigger/close actions. - Forgetting title/description structure in real dialogs.
- Wrapping dialog sections with extra containers that break
DialogHeader/DialogPanel/DialogFooterlayout; prefer header outside, `Form className="contents"` around panel + footer only. - Putting large body content outside
DialogPanelwhen scrolling is needed. - Missing explicit button
typeinside dialog forms/actions. - Using uncontrolled dialog patterns when the flow requires cross-component state coordination.
- Using non-coss composition APIs without verifying docs.
Useful particle references
- basic dialog scaffold:
p-dialog-1 - open dialog from another primitive flow:
p-dialog-2(menu -> dialog) - nested dialogs:
p-dialog-3 - close confirmation / unsaved changes flow:
p-dialog-4 - long scrollable content in panel:
p-dialog-5 - bare footer variant usage:
p-dialog-6 - responsive dialog/drawer variant:
p-drawer-12
coss Drawer
When to use
- Mobile-first overlay panels and bottom sheets.
- Form-heavy or multi-step overlays where popover is too constrained.
When NOT to use
- If the overlay should be a centered modal -> use Dialog instead.
- If the overlay should be a persistent side panel on desktop -> use Sheet instead.
- If you need a simple confirmation -> use AlertDialog instead.
Install
npx shadcn@latest add @coss/drawerManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Drawer,
DrawerCreateHandle,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerMenu,
DrawerMenuCheckboxItem,
DrawerMenuGroup,
DrawerMenuGroupLabel,
DrawerMenuItem,
DrawerMenuRadioGroup,
DrawerMenuRadioItem,
DrawerMenuSeparator,
DrawerPanel,
DrawerPopup,
DrawerMenuTrigger,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"Minimal pattern
<Drawer>
<DrawerTrigger>Open</DrawerTrigger>
<DrawerPopup>
<DrawerHeader>
<DrawerTitle>Drawer Title</DrawerTitle>
<DrawerDescription>Drawer Description</DrawerDescription>
</DrawerHeader>
<DrawerPanel>Content</DrawerPanel>
<DrawerFooter>
<DrawerClose>Close</DrawerClose>
</DrawerFooter>
</DrawerPopup>
</Drawer>Patterns from coss particles
- Portal forwarding: optional
portalPropsonDrawerPopup→ Base UIDrawer.Portal(keepMounted,container, …). See portal-props.md.
Key patterns
Drawer with handle:
<Drawer>
<DrawerTrigger render={<Button variant="outline" />}>Open Drawer</DrawerTrigger>
<DrawerPopup>
<DrawerCreateHandle />
<DrawerHeader>
<DrawerTitle>Edit Profile</DrawerTitle>
<DrawerDescription>Make changes to your profile here.</DrawerDescription>
</DrawerHeader>
<DrawerPanel>
{/* Form content */}
</DrawerPanel>
<DrawerFooter>
<Button>Save</Button>
<DrawerClose render={<Button variant="ghost" />}>Cancel</DrawerClose>
</DrawerFooter>
</DrawerPopup>
</Drawer>Responsive drawer + dialog (drawer on mobile, dialog on desktop): see p-drawer-12.
More examples
See p-drawer-1 through p-drawer-13 for inset, straight, scrollable, nested, snap points, mobile menu, and responsive patterns.
Common pitfalls
- Using drawer for desktop modal flows where dialog/sheet is clearer.
- Forgetting responsive switch logic when drawer is mobile-only variant.
- Breaking section layout by putting the whole dialog in a block-level
<form>; prefer header outside, `Form className="contents"` around panel + footer (see dialog/form skills).
Useful particle references
- inset variant:
p-drawer-4 - straight variant:
p-drawer-5 - scrollable content:
p-drawer-6 - nested drawers:
p-drawer-7 - snap points:
p-drawer-9 - mobile menu:
p-drawer-11 - responsive dialog:
p-drawer-12 - responsive menu:
p-drawer-13 - cross-overlay references:
p-dialog-1,p-popover-1,p-menu-2
coss Empty
When to use
- No-data/no-results states with guidance.
- Action-oriented recovery UIs when content lists are empty.
Install
npx shadcn@latest add @coss/emptyManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"Minimal pattern
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<Icon />
</EmptyMedia>
<EmptyTitle>No data</EmptyTitle>
<EmptyDescription>No data found</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button>Add data</Button>
</EmptyContent>
</Empty>Patterns from coss particles
Key patterns
Empty state with icon and action:
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<FolderIcon aria-hidden="true" />
</EmptyMedia>
<EmptyTitle>No projects yet</EmptyTitle>
<EmptyDescription>Get started by creating your first project.</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button>
<PlusIcon aria-hidden="true" />
New Project
</Button>
</EmptyContent>
</Empty>Always include an actionable next step (button, link) in EmptyContent.
More examples
See p-empty-1 for the core pattern.
Common pitfalls
- Presenting empty states without actionable next step.
- Using empty state component for loading/error states instead of dedicated primitives.
- Copy-only empty states with no context-specific guidance for recovery.
Useful particle references
- core patterns:
p-empty-1
coss Field
When to use
- Accessible field wrappers with labels, descriptions, and errors.
- Form control state wiring (
invalid,required, touched/error messaging).
Install
npx shadcn@latest add @coss/fieldManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
FieldValidity,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"Minimal pattern
<Field>
<FieldLabel>Name</FieldLabel>
<Input type="text" placeholder="Enter your name" />
<FieldDescription>Visible on your profile</FieldDescription>
<FieldError>Please enter a valid name</FieldError>
<FieldValidity>
{(validity) => (
{validity.error && <p>{validity.error}</p>}
)}
</FieldValidity>
</Field>Patterns from coss particles
Key patterns
Required field with error:
<Field name="email">
<FieldLabel>Email *</FieldLabel>
<Input type="email" required placeholder="name@company.com" />
<FieldDescription>We'll never share your email.</FieldDescription>
<FieldError>Please enter a valid email.</FieldError>
</Field>Field wrapping an autocomplete:
<Field name="framework">
<FieldLabel>Framework</FieldLabel>
<Autocomplete items={items}>
<AutocompleteInput placeholder="Search..." />
<AutocompletePopup>
<AutocompleteList>
{(item) => <AutocompleteItem key={item.value} value={item}>{item.label}</AutocompleteItem>}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
<FieldError />
</Field>More examples
See p-field-1 through p-field-9 for required, disabled, error, validity, input-group, autocomplete, and combobox field patterns.
Common pitfalls
- Rendering errors detached from the related control, breaking context.
- Missing
namein form flows, causing silent submit omissions. - Using field wrapper without corresponding label/description/error semantics.
Useful particle references
- required field:
p-field-2 - disabled field:
p-field-3 - with error:
p-field-4 - with validity:
p-field-5 - input group:
p-field-6 - autocomplete field:
p-field-7 - combobox field:
p-field-8 - combobox multiple field:
p-field-9 - form composition references:
p-form-1,p-form-2,p-input-group-24
coss Fieldset
When to use
- Grouped related controls under one legend/description.
- Complex forms requiring semantic grouping for radios/checkboxes.
Install
npx shadcn@latest add @coss/fieldsetManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset"Minimal pattern
<Fieldset>
<FieldsetLegend>Fieldset legend</FieldsetLegend>
</Fieldset>Patterns from coss particles
Key patterns
Fieldset grouping related fields:
<Fieldset>
<FieldsetLegend>Personal Information</FieldsetLegend>
<Field name="firstName">
<FieldLabel>First name</FieldLabel>
<Input type="text" />
</Field>
<Field name="lastName">
<FieldLabel>Last name</FieldLabel>
<Input type="text" />
</Field>
</Fieldset>Always include FieldsetLegend as the accessible group heading.
More examples
See p-fieldset-1 for the core pattern.
Common pitfalls
- Using ad-hoc div wrappers instead of semantic fieldset for grouped controls.
- Omitting
FieldsetLegend, reducing accessibility context. - Placing unrelated controls inside one fieldset, hurting form clarity.
Useful particle references
- core patterns:
p-fieldset-1 - form composition references:
p-form-1,p-form-2,p-input-group-24
coss Form
When to use
- Structured form validation and submission flows.
- Forms with field-level labels, descriptions, and errors.
- Integrations with external form libraries (for example React Hook Form / TanStack Form).
Install
npx shadcn@latest add @coss/formManual deps:
npm install @base-ui/react zodCanonical imports
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
} from "@/components/ui/field"
import { Form } from "@/components/ui/form"
import { Input } from "@/components/ui/input"Minimal pattern
<Form onSubmit={(e) => {/* handle submit */}}>
<Field>
<FieldLabel>Email</FieldLabel>
<Input name="email" type="email" required />
<FieldDescription>Used for account updates</FieldDescription>
<FieldError>Please enter a valid email.</FieldError>
</Field>
</Form>Patterns from coss particles
Formusage in particles is intentionally lightweight; use the Base UI forms handbook patterns below for deeper validation/library integrations.- Dialog / sheet / drawer: Header outside the form; `Form className="contents"` wraps panel + footer only (
p-dialog-1,p-sheet-1,p-sheet-2,p-drawer-10,p-drawer-12).
Patterns from coss/Base UI forms
- Submission mode: use
onSubmitfor nativeFormDatahandling; useonFormSubmitwhen you want parsed form values object from Base UI Form. - Field naming: set
nameon each field/control flow so values are included in submission. - Accessible names: prefer visible labels (
FieldLabel,SelectLabel, etc.); usearia-labelonly when no visible label exists. - Grouped controls: for radio/checkbox groups or multi-control sections, use fieldset-style grouping (
Fieldset+Field.Item) instead of ad-hoc wrappers. - Validation rendering: pair constraints/custom validation with
FieldError; keep error output semantically tied to the same field. - Textarea integration: use coss
Textareadirectly insideField; it already integrates with Base UI field control semantics, soFieldControl render={...}is not required for standard textarea usage. - External library integration: when using RHF/TanStack, forward refs/input refs to the underlying control and map invalid/touched/dirty state into
Field.
Common pitfalls
- Using
Formwithout field-level structure (Field, label, error). - Missing control
name(field not present in form submission payload). - Missing input
typeand buttontype. - Showing validation messages without matching invalid semantics.
- Using grouped checkboxes/radios without proper group legend/structure.
- Not forwarding refs in RHF/TanStack integration, which breaks focus-on-error behavior.
Useful particle references
p-form-1(basic integration)p-form-2(zod usage)
Further reading
- Base UI Forms handbook:
https://base-ui.com/react/handbook/forms.md
coss Frame
When to use
- Bordered app surfaces around content blocks.
- Container wrapper for data components like table, cards, and panes.
Install
npx shadcn@latest add @coss/frameManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import {
Frame,
FrameDescription,
FrameFooter,
FrameHeader,
FramePanel,
FrameTitle,
} from "@/components/ui/frame"Minimal pattern
<Frame>
<FrameHeader>
<FrameTitle>Title</FrameTitle>
<FrameDescription>Description</FrameDescription>
</FrameHeader>
<FramePanel>Content</FramePanel>
<FrameFooter>Footer</FrameFooter>
</Frame>Patterns from coss particles
Key patterns
Frame with header actions:
<Frame>
<FrameHeader className="flex items-center justify-between">
<div>
<FrameTitle>Users</FrameTitle>
<FrameDescription>Manage team members.</FrameDescription>
</div>
<Button size="sm">Add User</Button>
</FrameHeader>
<FramePanel>{/* Table or list content */}</FramePanel>
<FrameFooter>
<p className="text-muted-foreground text-sm">Showing 1-10 of 100</p>
</FrameFooter>
</Frame>Use Frame to normalize border/radius around heterogeneous inner content (tables, lists, cards).
More examples
See p-frame-1 through p-frame-3 for basic and separated panel patterns.
Common pitfalls
- Using nested frames excessively, causing dense double borders.
- Applying frame as layout grid replacement instead of content surface wrapper.
- Forgetting to align inner component width expectations (table/list full width).
Useful particle references
- separated panels:
p-frame-3
coss Group
When to use
- Connected controls with shared visual boundary.
- Composed action clusters using buttons, toggles, and menu triggers.
Install
npx shadcn@latest add @coss/groupManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Button } from "@/components/ui/button"
import { Group, GroupSeparator } from "@/components/ui/group"Minimal pattern
<Group>
<Button>Button</Button>
<GroupSeparator />
<Button>Button</Button>
</Group>Patterns from coss particles
Key patterns
Button group with separator:
<Group>
<Button variant="outline">Copy</Button>
<GroupSeparator />
<Button variant="outline">Paste</Button>
<GroupSeparator />
<Button variant="outline">Cut</Button>
</Group>Group with input and button:
<Group>
<Input type="text" placeholder="Enter URL..." />
<GroupSeparator />
<Button>Go</Button>
</Group>Sizes: sm, default, lg. Orientation: vertical via orientation="vertical".
More examples
See p-group-1 through p-group-9 for input, sizes, disabled, vertical, and labeled text patterns.
Common pitfalls
- Forgetting
GroupSeparatorbetween controls in connected groups. - Mixing control sizes/variants that break shared group silhouette.
- Using standalone controls where a grouped action model is expected.
Useful particle references
- with input:
p-group-2 - small size:
p-group-3 - large size:
p-group-4 - with disabled button:
p-group-5 - with default buttons:
p-group-6 - with start labeled text:
p-group-7 - with end text:
p-group-8 - vertical:
p-group-9
coss Input Group
When to use
- Inputs/textareas that need inline or block addons.
- Input composition with icons, buttons, labels, badges, and shortcuts.
Install
npx shadcn@latest add @coss/input-groupManual deps:
npm install @base-ui/reactCanonical imports
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
InputGroupText,
} from "@/components/ui/input-group"Minimal pattern
<InputGroup>
<InputGroupInput type="email" placeholder="Email" />
<InputGroupAddon>
<MailIcon />
</InputGroupAddon>
</InputGroup>Critical invariant
InputGroupAddon must be after InputGroupInput/InputGroupTextarea in DOM order for proper focus behavior.
Patterns from coss particles
Key patterns
Search input with icon:
<InputGroup>
<InputGroupInput aria-label="Search" placeholder="Search..." type="search" />
<InputGroupAddon>
<SearchIcon aria-hidden="true" />
</InputGroupAddon>
</InputGroup>URL prefix with text addon:
<InputGroup>
<InputGroupAddon>
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="example.com" />
</InputGroup>Input with interactive button addon:
<InputGroup>
<InputGroupInput placeholder="Enter value..." />
<InputGroupAddon>
<Button size="icon" variant="ghost" aria-label="Clear">
<XIcon aria-hidden="true" />
</Button>
</InputGroupAddon>
</InputGroup>InputGroupAddon must be after InputGroupInput/InputGroupTextarea in DOM order for proper focus behavior.
More examples
See p-input-group-1 through p-input-group-29 for icons, text prefixes, interactive addons, textarea layouts, and stateful patterns.
Common pitfalls
- Using
Input/Textareadirectly instead ofInputGroupInput/InputGroupTextarea. - Wrong addon DOM order.
- Missing explicit input types.
Useful particle references
- icon addon + search baseline:
p-input-group-1,p-input-group-2,p-input-group-13,p-input-group-14,p-input-group-20 - prefix/suffix text addons (url/domain/currency):
p-input-group-3,p-input-group-4,p-input-group-5,p-input-group-6 - interactive addons (buttons/badge/kbd/menu/clear/voice):
p-input-group-7,p-input-group-8,p-input-group-9,p-input-group-10,p-input-group-11,p-input-group-12,p-input-group-18,p-input-group-21,p-input-group-22,p-input-group-23 - textarea/editor-style layouts with block-end/start addons:
p-input-group-17,p-input-group-19,p-input-group-27,p-input-group-28,p-input-group-29 - stateful/validation patterns (disabled/loading/password strength):
p-input-group-15,p-input-group-16,p-input-group-24,p-input-group-26
coss Input
When to use
- Single-line text entry with variants and addons.
- Email/password/search/file and other typed input flows.
Install
npx shadcn@latest add @coss/inputManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Input } from "@/components/ui/input"Minimal pattern
<Input aria-label="Email" type="email" placeholder="name@company.com" />Always set type explicitly on Input (text, email, password, search, file, etc.). Do not rely on browser defaults. For form fields, prefer wrapping Input with Field + FieldLabel + FieldError instead of standalone usage.
Patterns from coss particles
Key patterns
Field-wrapped input (preferred for forms):
<Field>
<FieldLabel>Email</FieldLabel>
<Input type="email" placeholder="name@company.com" />
<FieldError>Please enter a valid email.</FieldError>
</Field>Input with addon (InputGroup):
<InputGroup>
<InputGroupInput aria-label="Search" placeholder="Search" type="search" />
<InputGroupAddon>
<SearchIcon aria-hidden="true" />
</InputGroupAddon>
</InputGroup>Sizes: sm, default, lg. Always specify type explicitly.
More examples
- small size:
p-input-2 - large size:
p-input-3 - disabled:
p-input-4 - file:
p-input-5 - with label:
p-input-6 - with button:
p-input-7 - form integration:
p-form-1
Common pitfalls
- Omitting explicit
typeand relying on browser defaults. - Using icon-only affordances without label/aria context.
- Applying heavy class overrides before using built-in size/variant props.
Useful particle references
See p-input-1 through p-input-7 for size/variant combinations, p-form-1 for form integration.
coss Kbd
When to use
- Keyboard shortcut keycaps near commands.
- Single or grouped key hint display in action UIs.
Install
npx shadcn@latest add @coss/kbdManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import { Kbd, KbdGroup } from "@/components/ui/kbd"Minimal pattern
<Kbd>K</Kbd>Patterns from coss particles
Key patterns
Multi-key shortcut with KbdGroup (each key gets its own Kbd):
<KbdGroup>
<Kbd>⌘</Kbd>
<Kbd>K</Kbd>
</KbdGroup>Button with keyboard shortcut:
<Button variant="outline">
Print
<KbdGroup className="-me-1">
<Kbd>⌘</Kbd>
<Kbd>P</Kbd>
</KbdGroup>
</Button>Single key shortcut in a button:
<Button variant="outline">
Save
<Kbd className="-me-1">⌘S</Kbd>
</Button>More examples
- input group integration:
p-input-group-11
Common pitfalls
- Placing multi-key sequences in a single
KbdwhenKbdGroupis clearer. - Using decorative keycaps without tying them to nearby actionable controls.
- Overusing kbd hints in simple UIs, adding noise instead of clarity.
Useful particle references
- input group:
p-input-group-11
coss Label
When to use
- Visible accessible labels for inputs and controls.
- Simple
htmlFor/idassociations in forms and settings UIs.
Install
npx shadcn@latest add @coss/labelManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import { Label } from "@/components/ui/label"Minimal pattern
<Label htmlFor="email">Email</Label>Patterns from coss particles
Key patterns
Label paired with input:
const id = useId()
<div className="flex flex-col gap-2">
<Label htmlFor={id}>Email</Label>
<Input id={id} type="email" placeholder="name@example.com" />
</div>Label wrapping a checkbox:
<Label>
<Checkbox />
Accept terms and conditions
</Label>Prefer FieldLabel within Field for validation-aware forms.
More examples
See p-field-1, p-input-1, p-checkbox-1 for label-in-form patterns.
Common pitfalls
- Using
aria-labelwhen visibleLabeltext exists and can be associated. - Mismatching
htmlFor/idbetween label and control. - Using label component as generic typography instead of form labeling.
Useful particle references
- with checkbox:
checkbox-demo - label-specific particles: no dedicated
p-label-*family; use form referencesp-field-1,p-input-1,p-checkbox-1.
coss Menu
When to use
- Contextual action lists and dropdown commands.
- Mixed item types (regular, checkbox, radio, nested submenu).
When NOT to use
- If the user needs to search/filter actions -> use Command instead.
- If the content is rich informational (not actions) -> use Popover instead.
- If the overlay is a full modal flow -> use Dialog instead.
Install
npx shadcn@latest add @coss/menuManual deps and theme var from docs:
npm install @base-ui/reactAlso include the destructive foreground CSS variable snippet from the coss menu docs when doing manual setup.
Canonical imports
import {
Menu,
MenuCheckboxItem,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuLinkItem,
MenuPopup,
MenuRadioGroup,
MenuRadioItem,
MenuSeparator,
MenuShortcut,
MenuSub,
MenuSubPopup,
MenuSubTrigger,
MenuTrigger,
} from "@/components/ui/menu"Minimal pattern
<Menu>
<MenuTrigger>Open</MenuTrigger>
<MenuPopup>
<MenuItem>Profile</MenuItem>
<MenuSeparator />
<MenuCheckboxItem>Shuffle</MenuCheckboxItem>
</MenuPopup>
</Menu>Use popup positioning props like align / sideOffset only when a layout needs explicit tuning.
Patterns from coss particles
- Portal forwarding: optional
portalPropsonMenuPopup→ Base UIMenu.Portal(keepMounted,container, …). See portal-props.md. - Use
MenuTrigger render={<Button ... />}as the default trigger composition. - Use
openOnHoveronMenuTriggeronly for explicit hover-driven UX. - Use
MenuLinkItemfor navigation links. If migrating fromMenuItem render={<Link href="..." />}, change the component toMenuLinkItembut keep `render={<Link … />}` — do not swap tohrefalone with a router Link. UsehrefonMenuLinkItemonly for plain anchors. - Use
MenuItem closeOnClickfor action menus where selection should always dismiss the popup. - Use
MenuCheckboxItem variant="switch"for toggle-style preferences. - Use
MenuRadioGroup+MenuRadioItemwith adefaultValuewhen enforcing single-choice selection. - Use
MenuShortcutto display keyboard hints in dense command menus. - Use
variant="destructive"on dangerous actions. - For responsive action menus, keep desktop on
Menuand switch mobile toDrawerMenu/DrawerMenuTrigger/DrawerMenuItempatterns. - In
DrawerMenuflows, wrap actionable rows withDrawerClose render={<DrawerMenuItem />}when selection should dismiss the drawer.
Common pitfalls
- Forgetting
MenuGrouparound grouped structures. - Missing submenu pair (
MenuSubTrigger+MenuSubPopup) for nested actions. - Mixing navigation and action items without clear close behavior (
closeOnClick) and semantics.
Useful particle references
- full-featured menu (groups, checkbox/radio, submenus, destructive):
p-menu-1 - hover-activated trigger pattern:
p-menu-2 - checkbox item pattern:
p-menu-3 - radio group pattern:
p-menu-4 - link/navigation with
MenuLinkItem render={<Link … />}:p-menu-5 - grouped sections with labels + separators:
p-menu-6 - nested submenu pattern:
p-menu-7 - force close on click actions:
p-menu-8 - switch-style checkbox items:
p-menu-9 - cross-component example:
p-dialog-2(menu opening dialog) - responsive menu/drawer variant:
p-drawer-13
coss Meter
When to use
- Bounded scalar measurement display (not task progress).
- Quality/capacity indicators with min/max semantics.
When NOT to use
- If displaying task completion or async progress -> use Progress instead.
- If the indicator is indeterminate -> use Spinner or Progress instead.
Install
npx shadcn@latest add @coss/meterManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Meter, MeterLabel, MeterValue } from "@/components/ui/meter"Minimal pattern
<Meter value={40}>
<MeterLabel>Progress</MeterLabel>
<MeterValue />
</Meter>Patterns from coss particles
Key patterns
Meter with formatted value and range:
<Meter value={75} min={0} max={100}>
<div className="flex justify-between text-sm">
<MeterLabel>Storage</MeterLabel>
<MeterValue>{({ formattedValue }) => `${formattedValue} used`}</MeterValue>
</div>
</Meter>Minimal meter without label:
<Meter value={40} aria-label="Progress" />More examples
See p-meter-1 through p-meter-4 for label, formatted value, and range patterns.
Common pitfalls
- Using meter to represent completion tasks better suited for
Progress. - Missing min/max context when values are not obvious to the user.
- Treating meter as interactive control rather than read-only indicator.
Useful particle references
- without label and value:
p-meter-2 - with formatted value:
p-meter-3 - with range:
p-meter-4
coss Number Field
When to use
- Numeric entry with increment/decrement controls.
- Bounded stepper-style quantity/amount inputs.
Install
npx shadcn@latest add @coss/number-fieldManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
NumberField,
NumberFieldDecrement,
NumberFieldGroup,
NumberFieldIncrement,
NumberFieldInput,
NumberFieldScrubArea,
} from "@/components/ui/number-field"Minimal pattern
<NumberField defaultValue={0}>
<NumberFieldScrubArea label="Quantity" />
<NumberFieldGroup>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldGroup>
</NumberField>For form-bound numeric inputs, prefer wrapping NumberField with Field + FieldLabel + FieldError instead of standalone usage.
Patterns from coss particles
Key patterns
Number field with external label and bounds:
<Field name="quantity">
<FieldLabel>Quantity</FieldLabel>
<NumberField defaultValue={1} min={0} max={99}>
<NumberFieldGroup>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldGroup>
</NumberField>
<FieldError />
</Field>Number field with scrub area (drag to adjust):
<NumberField defaultValue={50}>
<NumberFieldScrubArea label="Brightness" />
<NumberFieldGroup>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldGroup>
</NumberField>Sizes: sm, default, lg on NumberFieldGroup.
More examples
See p-number-field-1 through p-number-field-9 for sizes, disabled, scrub, range, formatted value, and step patterns.
Common pitfalls
- Treating number field value as free-form text without numeric bounds/steps.
- Missing increment/decrement controls in stepper-style UIs where expected.
- Not validating min/max constraints and resulting clamped behavior.
Useful particle references
- small size:
p-number-field-2 - large size:
p-number-field-3 - disabled:
p-number-field-4 - with external label:
p-number-field-5 - with scrub:
p-number-field-6 - with range:
p-number-field-7 - with formatted value:
p-number-field-8 - with step:
p-number-field-9
coss OTP Field
When to use
- One-time passcode entry with segmented slots.
- Verification code flows with strict length formatting.
Install
npx shadcn@latest add @coss/otp-fieldManual deps from docs:
npm install @base-ui/react lucide-reactCanonical imports
import {
OTPField,
OTPFieldInput,
OTPFieldSeparator,
} from "@/components/ui/otp-field"Minimal pattern
<OTPField aria-label="Verification code" length={6}>
<OTPFieldInput aria-label="Character 1 of 6" />
<OTPFieldInput aria-label="Character 2 of 6" />
<OTPFieldInput aria-label="Character 3 of 6" />
<OTPFieldSeparator />
<OTPFieldInput aria-label="Character 4 of 6" />
<OTPFieldInput aria-label="Character 5 of 6" />
<OTPFieldInput aria-label="Character 6 of 6" />
</OTPField>Patterns from coss particles
Key patterns
OTP with label and controlled value:
const [value, setValue] = useState("")
<div className="flex flex-col gap-2">
<Label>Verification code</Label>
<OTPField
length={6}
value={value}
onValueChange={setValue}
>
<OTPFieldInput aria-label="Character 1 of 6" />
<OTPFieldInput aria-label="Character 2 of 6" />
<OTPFieldInput aria-label="Character 3 of 6" />
<OTPFieldSeparator />
<OTPFieldInput aria-label="Character 4 of 6" />
<OTPFieldInput aria-label="Character 5 of 6" />
<OTPFieldInput aria-label="Character 6 of 6" />
</OTPField>
</div>Digit-only SMS-style codes use Base UI’s default validationType (numeric) and matching inputMode; set those props explicitly only when you need different behavior.
Ensure slot count matches length.
More examples
See p-otp-field-1 through p-otp-field-4 and p-otp-field-6 through p-otp-field-10 for sizes, separators, label, custom sanitization, auto-validation, alphanumeric codes, placeholder hints, and masked entry.
Common pitfalls
- Slot count mismatch with
length, causing broken OTP UX. - Missing
aria-labelwhen no visible label is present. - Using OTP slots for arbitrary text input instead of fixed verification codes.
Useful particle references
- large:
p-otp-field-2 - with separator:
p-otp-field-3 - with label:
p-otp-field-4 - custom sanitization:
p-otp-field-6 - auto validation:
p-otp-field-7 - alphanumeric:
p-otp-field-8 - placeholder hints:
p-otp-field-9 - masked entry:
p-otp-field-10
coss Pagination
When to use
- Paged navigation over long result sets.
- Prev/next and index controls paired with data tables/lists.
Install
npx shadcn@latest add @coss/paginationManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"Minimal pattern
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>Patterns from coss particles
Key patterns
Full pagination with active page:
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>More examples
See p-pagination-1 through p-pagination-3 for various pagination layouts.
Common pitfalls
- Using pagination controls without synchronizing data/page state.
- Mixing pagination with infinite-scroll UX in the same surface.
- Missing disabled-state handling on prev/next boundaries.
Useful particle references
- core patterns:
p-pagination-1,p-pagination-2,p-pagination-3
coss Popover
When to use
- Contextual floating content near a trigger.
- Inline editing/help panels without full modal lock.
When NOT to use
- If the content requires user focus/action before dismissal -> use Dialog instead.
- If the content is just a short text hint -> use Tooltip instead.
- If it's a list of actions -> use Menu instead.
Install
npx shadcn@latest add @coss/popoverManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Popover,
PopoverClose,
PopoverCreateHandle,
PopoverDescription,
PopoverPopup,
PopoverTitle,
PopoverTrigger,
} from "@/components/ui/popover"Minimal pattern
<Popover>
<PopoverTrigger render={<Button variant="outline" />}>Open Popover</PopoverTrigger>
<PopoverPopup>
<PopoverTitle>Popover Title</PopoverTitle>
<PopoverDescription>Popover Description</PopoverDescription>
<PopoverClose render={<Button variant="outline" />}>Close</PopoverClose>
</PopoverPopup>
</Popover>Patterns from coss particles
- Portal forwarding: optional
portalPropsonPopoverPopup→ Base UIPopover.Portal(keepMounted,container, …). See portal-props.md. - Form-in-popover: use
PopoverPopupas a lightweight form container (for example feedback forms withForm+Field+Textarea). - Dismiss controls: use
PopoverCloseboth for footer actions and icon close buttons (aria-label+render={<Button size="icon" .../>}). - Tooltip-like popovers: use
tooltipStylefor info-icon helper content where tooltip density is preferred. - Detached triggers: use
PopoverCreateHandle+ sharedhandle/payloadon multiplePopoverTriggers to animate one popup across triggers. - Position tuning: only add
side,align,sideOffset,alignOffsetwhen default anchoring is not sufficient.
Common pitfalls
- Treating Popover as a modal replacement when the flow needs full modal behavior (use Dialog/AlertDialog instead).
- Forgetting
rendercomposition on trigger/close when using coss buttons. - Missing accessible names on icon-only triggers or close controls.
- Using detached trigger handles without stable payload/content mapping.
- Copying Tooltip patterns directly without checking
tooltipStyleand popover semantics.
Useful particle references
- baseline popover with form content:
p-popover-1 - close controls (icon + action button):
p-popover-2 - detached trigger handle pattern:
p-popover-3 - tooltip-style popover usage example:
p-input-group-7
coss Preview Card
When to use
- Hover/focus-triggered rich preview content.
- Contextual details for users/entities without full navigation.
Install
npx shadcn@latest add @coss/preview-cardManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Button } from "@/components/ui/button"
import {
PreviewCard,
PreviewCardPopup,
PreviewCardTrigger,
} from "@/components/ui/preview-card"Minimal pattern
<PreviewCard>
<PreviewCardTrigger>Open Preview Card</PreviewCardTrigger>
<PreviewCardPopup>Preview Card Content</PreviewCardPopup>
</PreviewCard>Patterns from coss particles
- Portal forwarding: optional
portalPropsonPreviewCardPopup→ Base UIPreviewCard.Portal(keepMounted,container, …). See portal-props.md.
Key patterns
Preview card with rich content:
<PreviewCard>
<PreviewCardTrigger render={<a href="/user/johndoe" />}>
@johndoe
</PreviewCardTrigger>
<PreviewCardPopup className="w-80">
<div className="flex items-center gap-3">
<Avatar>
<AvatarImage src="/avatar.png" alt="John Doe" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-semibold">John Doe</p>
<p className="text-muted-foreground text-xs">Software Engineer</p>
</div>
</div>
</PreviewCardPopup>
</PreviewCard>More examples
See p-preview-card-1 for the core pattern.
Common pitfalls
- Using preview card for critical workflows requiring explicit modal interaction.
- Missing accessible trigger labels when using icon-only triggers.
- Rendering heavy async content on every hover without throttling/caching strategy.
Useful particle references
- core patterns:
p-preview-card-1
coss Progress
When to use
- Task completion and async operation progress bars.
- Indeterminate or determinate status during loading pipelines.
When NOT to use
- If displaying a bounded measurement (not task completion) -> use Meter instead.
- If the loading state is indeterminate with no percentage -> consider Spinner.
Install
npx shadcn@latest add @coss/progressManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Progress,
ProgressLabel,
ProgressValue,
} from "@/components/ui/progress"Minimal pattern
<Progress value={40} />Patterns from coss particles
Key patterns
Progress with label and value display:
<Progress value={60}>
<div className="flex justify-between text-sm">
<ProgressLabel>Uploading...</ProgressLabel>
<ProgressValue />
</div>
</Progress>Determinate progress: bind a numeric value (0-100) for known completion states. Indeterminate loading: omit value or pass null when progress cannot be measured.
More examples
- with label and value:
p-progress-2 - with formatted value:
p-progress-3
Common pitfalls
- Using progress without text/context for what operation is progressing.
- Using determinate values when state is actually unknown/indeterminate.
- Using progress for static score displays that should use
Meter.
Useful particle references
See p-progress-1 through p-progress-3 for animated, labeled, and formatted value patterns.
coss Radio Group
When to use
- Mutually exclusive option selection.
- Single-choice settings with clear option labels.
When NOT to use
- If multiple options can be selected -> use CheckboxGroup instead.
- If options are many and need search/filtering -> use Select or Combobox instead.
- If the choices are binary (on/off) -> use Switch or Checkbox instead.
Install
npx shadcn@latest add @coss/radio-groupManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Label } from "@/components/ui/label"
import { Radio, RadioGroup } from "@/components/ui/radio-group"Minimal pattern
<RadioGroup defaultValue="next">
<Label>
<Radio value="next" /> Next.js
</Label>
<Label>
<Radio value="vite" /> Vite
</Label>
<Label>
<Radio value="astro" /> Astro
</Label>
</RadioGroup>For form-bound single-choice groups, prefer Field + Fieldset composition to keep legend and validation semantics consistent.
Patterns from coss particles
Key patterns
Radio group with descriptions:
<RadioGroup defaultValue="comfortable" aria-label="Spacing preference">
<Label className="flex items-start gap-3">
<Radio value="default" />
<div>
<span className="font-medium">Default</span>
<p className="text-muted-foreground text-xs">Standard spacing for most layouts.</p>
</div>
</Label>
<Label className="flex items-start gap-3">
<Radio value="comfortable" />
<div>
<span className="font-medium">Comfortable</span>
<p className="text-muted-foreground text-xs">Extra padding for readability.</p>
</div>
</Label>
</RadioGroup>Controlled radio group:
const [value, setValue] = useState("default")
<RadioGroup value={value} onValueChange={setValue}>
...
</RadioGroup>More examples
See p-radio-group-1 through p-radio-group-5 for disabled, description, card-style, and form integration patterns.
Common pitfalls
- Using radios for multi-select behavior that requires checkbox group.
- Missing label association for each radio option.
- Handling selected value as array when radio group returns single value.
Useful particle references
- disabled:
p-radio-group-2 - with description:
p-radio-group-3 - card style:
p-radio-group-4 - form integration:
p-radio-group-5 - form composition references:
p-form-1,p-form-2,p-input-group-24
coss Scroll Area
When to use
- Constrained-height scroll containers with styled viewport.
- Scrollable lists/logs/panels embedded in fixed layouts.
Install
npx shadcn@latest add @coss/scroll-areaManual deps from docs:
npm install @base-ui/reactCanonical imports
import { ScrollArea } from "@/components/ui/scroll-area"Minimal pattern
<ScrollArea className="h-64 rounded-md border">
<div className="p-4">
Just as suddenly as it had begun, the sensation stopped, leaving Alice
feeling slightly disoriented. She looked around and realized that the room
hadn't changed at all - it was she who had grown smaller, shrinking down to
a fraction of her previous size. Alice felt herself growing larger and
larger, filling up the entire room until she feared she might burst. The
sensation was both thrilling and terrifying, as if she were expanding beyond
the confines of her own body. She wondered if this was what it felt like to
be a balloon, swelling with air until it could hold no more.
</div>
</ScrollArea>Patterns from coss particles
Key patterns
Horizontal scrolling (use wide inner content, not an orientation prop):
<ScrollArea className="max-w-96 rounded-lg border">
<div className="flex w-max gap-4 p-4">
{items.map((item) => (
<div key={item} className="w-32 shrink-0">{item}</div>
))}
</div>
</ScrollArea>Scroll fade edges:
<ScrollArea className="h-64" scrollFade>
<div className="p-4">{/* Long content */}</div>
</ScrollArea>Fill viewport for flex layouts (e.g. sidebar footers with mt-auto):
<ScrollArea className="flex-1 min-h-0" fill>
<div className="flex h-full flex-col">
<nav>{/* main items */}</nav>
<footer className="mt-auto">{/* pinned footer */}</footer>
</div>
</ScrollArea>fill defaults to false. Use it only when the content wrapper must stretch to the viewport height—not for lists, comboboxes, or other content-sized scroll areas.
ScrollArea always renders both scrollbars internally -- horizontal scroll is driven by inner content width exceeding the container, not by a prop. Also supports scrollbarGutter for reserving scrollbar space.
clampContentMinWidth defaults to true and sets minWidth: 0 on the content wrapper to avoid spurious horizontal scroll in vertical layouts (Base UI uses min-width: fit-content). Wide children (w-max, table min-width) still scroll horizontally. Set clampContentMinWidth={false} only if horizontal scroll breaks and the child has no explicit width.
More examples
See p-scroll-area-1 through p-scroll-area-5 for vertical, horizontal, both axes, fade, and gutter patterns.
Common pitfalls
- Forgetting explicit height/constraint, resulting in non-scrollable container.
- Nesting multiple scroll areas that compete for wheel/touch events.
- Using scroll area where native page scrolling is simpler and clearer.
- Using
fillon every scroll area—default isfalse; opt in only for flex layouts that need full viewport height (e.g.mt-autofooters). Pair withflex-1 min-h-0on the root andh-full flex-colon the inner wrapper. - Disabling
clampContentMinWidthunless horizontal scroll actually regresses—defaulttruefixes spurious horizontal bars in vertical-first layouts.
Useful particle references
- scroll fade:
p-scroll-area-4 - horizontal scroll:
p-scroll-area-2 - scrollbar gutter:
p-scroll-area-5 - both scrollbars:
p-scroll-area-3
coss Select
When to use
- Single-choice selection from a predefined list.
- Select-style triggers with popup options.
When NOT to use
- If the user needs to type/filter options -> use Combobox instead.
- If the list is very short (2-3 items) with visible options -> consider RadioGroup.
- If the selection drives complex search/autocomplete -> use Autocomplete instead.
Install
npx shadcn@latest add @coss/selectManual deps:
npm install @base-ui/reactCanonical imports
import {
Select,
SelectGroup,
SelectGroupLabel,
SelectItem,
SelectLabel,
SelectPopup,
SelectSeparator,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"Minimal pattern
const items = [
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
]
<Select items={items}>
<SelectTrigger>
<SelectValue placeholder="Select framework" />
</SelectTrigger>
<SelectPopup>
<SelectLabel>Frameworks</SelectLabel>
{items.map((item) => (
<SelectItem key={item.value} value={item}>
{item.label}
</SelectItem>
))}
</SelectPopup>
</Select>Prefer this items-first pattern for migration work to keep options known before hydration and avoid SSR mismatch edge cases.
For form-bound selects, prefer wrapping with Field + FieldLabel + FieldError so value, label, and validation stay semantically linked.
Patterns from coss particles
- Field composition: in forms, place
SelectinsideFieldwrappers (seep-select-23,p-form-1,p-form-2). - Trigger composition: keep
SelectTriggeras the interaction entry point and avoid RadixasChildassumptions from other primitives; where composition is needed, prefer documented coss/Base UIrenderpatterns for supported parts. - Multiple selection: use
multiplewith array values (for exampledefaultValue={["javascript", "typescript"]}) and a customSelectValuerender function for compact summaries. - Object values: use full objects in
SelectItem value={item}withitemToStringValuefor stable form value serialization. - Grouped options: use
SelectGroup+SelectGroupLabel; combine withSelectSeparatorbetween groups when needed. - Disabled options: pass
disabledon individualSelectItemrows (for unavailable choices). - Rich row/trigger rendering: render custom content (icons, avatars, secondary text) in both
SelectValueandSelectItem; adjust row density viaclassNamewhere needed. - Alignment tuning: use
alignItemWithTrigger={false}only when the default selected-item alignment causes layout issues.
Portal forwarding
- Portal forwarding: optional
portalPropsonSelectPopup→ Base UISelect.Portal(keepMounted,container, …). See portal-props.md.
Common pitfalls
- Keeping children-only Radix select patterns without adding
items. - Forgetting to render
SelectValueinsideSelectTrigger. - Placing placeholder on the wrong part; use
placeholderonSelectValuewhen needed. - Using object item values without
itemToStringValuewhen stable string value serialization is required. - Treating
multipleselect values as scalars instead of arrays. - Mixing select and combobox APIs without validating docs.
Useful particle references
- basic select + sizing:
p-select-1,p-select-2,p-select-3 - grouped/labeled/select field patterns:
p-select-6,p-select-11,p-select-23 - multiple selection summary rendering:
p-select-7 - object values + rich option content:
p-select-10,p-select-17,p-select-20 - disabled options:
p-select-12 - related pattern:
p-combobox-18(SelectButtonwith combobox trigger)
coss Separator
When to use
- Visual/semantic separation between related blocks.
- Section dividers in menus, cards, and grouped controls.
Install
npx shadcn@latest add @coss/separatorManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Separator } from "@/components/ui/separator"Minimal pattern
<div className="flex flex-col gap-2">
<span className="text-sm">Section A</span>
<Separator />
<span className="text-sm">Section B</span>
</div>Patterns from coss particles
Key patterns
Horizontal separator (default):
<Separator />Vertical separator inline:
<div className="flex items-center gap-4">
<span>Home</span>
<Separator orientation="vertical" className="h-4" />
<span>Settings</span>
</div>More examples
See p-separator-1 for the core pattern. Also used within p-menu-1, p-group-1, and p-input-group-7.
Common pitfalls
- Adding separators between every small element, creating visual clutter.
- Using separators where spacing alone communicates grouping better.
- Forgetting orientation/context in dense vertical command layouts.
Useful particle references
- core patterns:
p-separator-1 - cross-primitive dividers:
p-menu-1,p-group-1,p-input-group-7
coss Sheet
When to use
- Side-panel overlays for settings/details/workflows.
- Persistent context panels opened from main content area.
When NOT to use
- If the overlay should be centered and focused -> use Dialog instead.
- If the overlay is a mobile-only bottom panel -> use Drawer instead.
- If the flow is a destructive confirmation -> use AlertDialog instead.
Install
npx shadcn@latest add @coss/sheetManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Sheet,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetPanel,
SheetPopup,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet"Minimal pattern
<Sheet>
<SheetTrigger>Open</SheetTrigger>
<SheetPopup>
<SheetHeader>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</SheetDescription>
</SheetHeader>
<SheetPanel>Content</SheetPanel>
<SheetFooter>
<SheetClose>Close</SheetClose>
</SheetFooter>
</SheetPopup>
</Sheet>Patterns from coss particles
- Portal forwarding: optional
portalPropsonSheetPopup→ Base UIDialog.Portal(keepMounted,container, …). See portal-props.md.
Key patterns
Sheet from the right side with form:
<Sheet>
<SheetTrigger render={<Button variant="outline" />}>Edit Profile</SheetTrigger>
<SheetPopup side="right">
<SheetHeader>
<SheetTitle>Edit Profile</SheetTitle>
<SheetDescription>Make changes to your profile here.</SheetDescription>
</SheetHeader>
<SheetPanel className="flex flex-col gap-4">
<Field name="name">
<FieldLabel>Name</FieldLabel>
<Input type="text" />
</Field>
</SheetPanel>
<SheetFooter>
<SheetClose render={<Button variant="ghost" />}>Cancel</SheetClose>
<Button>Save</Button>
</SheetFooter>
</SheetPopup>
</Sheet>Side options: top, right, bottom, left.
More examples
See p-sheet-1 through p-sheet-3 for inset and side sheet patterns.
Common pitfalls
- Using sheet for simple tooltip/popover hints that do not need panel behavior.
- Missing close actions and focus-return verification on open/close cycle.
- Overloading sheet with multi-step form logic better handled by dedicated route/modal flow.
Useful particle references
- sheet with inset:
p-sheet-2 - side sheets:
p-sheet-3 - cross-overlay references:
p-dialog-1,p-popover-1,p-menu-2
coss Sidebar
When to use
- Persistent app shell navigation and grouped links.
- Collapsible/structured side navigation for dashboard layouts.
Install
npx shadcn@latest add @coss/sidebarManual deps from docs:
npm install @base-ui/reactCanonical imports
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarRail,
SidebarSeparator,
SidebarTrigger,
useSidebar,
} from "@/components/ui/sidebar"Minimal pattern
<SidebarProvider>
<Sidebar>
<SidebarHeader>Workspace</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>Dashboard</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>{/* Main page content */}</SidebarInset>
</SidebarProvider>Patterns from coss particles
Key patterns
Sidebar with grouped navigation and footer:
<SidebarProvider>
<Sidebar>
<SidebarHeader>
<h2 className="text-lg font-semibold">App Name</h2>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Main</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton render={<a href="/dashboard" />}>
Dashboard
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton render={<a href="/projects" />}>
Projects
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>Settings</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
<SidebarRail />
</Sidebar>
<SidebarInset>{/* Page content */}</SidebarInset>
</SidebarProvider>Key composition rules:
- Wrap app with
SidebarProviderat the layout level. - Use
SidebarContent(not "SidebarPanel") as the scrollable body between header/footer. It usesScrollAreawithfillso flex children (e.g.mt-autofooters) can pin to the bottom. - Navigation items use
SidebarMenu>SidebarMenuItem>SidebarMenuButton. - For link items, use
rendercomposition:<SidebarMenuButton render={<a href="..." />}>. Do not useasChild-- sidebar follows the samerenderpattern as all other coss primitives. - Use
SidebarTriggerfor the collapse/expand toggle. - Use
SidebarInsetfor the main content area next to the sidebar. SidebarRailadds a slim hover-to-expand rail in collapsed state.
More examples
See p-toolbar-1, p-breadcrumb-1, p-tabs-1, p-menu-1 for related app-shell patterns.
Common pitfalls
- Using non-existent parts like "SidebarPanel" or "SidebarItem" -- the correct names are
SidebarContentandSidebarMenuItem. - Forgetting
SidebarProviderwrapper, which manages collapse state and mobile responsiveness. - Skipping the
SidebarMenu>SidebarMenuItem>SidebarMenuButtonhierarchy for nav items. - Missing responsive collapse strategy for narrow/mobile layouts.
- Replacing
SidebarContent's scroll area with a rawScrollAreawithoutfillwhen the body usesmt-autoto pin footers—usefill(see scroll-area primitive docs).
Useful particle references
- sidebar-specific particles: no dedicated
p-sidebar-*family currently. - app-shell references:
p-toolbar-1,p-breadcrumb-1,p-tabs-1,p-menu-1
coss Skeleton
When to use
- Loading placeholders matching final layout density.
- Perceived-performance improvement during fetch/render latency.
Install
npx shadcn@latest add @coss/skeletonManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import { Skeleton } from "@/components/ui/skeleton"Minimal pattern
<Skeleton className="size-10 rounded-full" />Patterns from coss particles
Key patterns
Card skeleton composition (match the final layout geometry):
<div className="flex items-center gap-4">
<Skeleton className="size-10 rounded-full" />
<div className="flex flex-1 flex-col">
<Skeleton className="my-0.5 h-4 max-w-54" />
<Skeleton className="my-0.5 h-4 w-1/2" />
</div>
<Skeleton className="h-7 w-19" />
</div>Shape matching: mirror final text/image/button geometry to reduce content shift. State handoff: remove skeleton immediately when data is ready to avoid double-render.
More examples
- skeleton-only layout:
p-skeleton-2 - full loading-to-loaded flow:
p-skeleton-1
Common pitfalls
- Mismatch between skeleton layout and final content layout causing jarring swap.
- Leaving skeleton visible after load completion due missing state transition.
- Using skeleton for very short operations where spinner/text is clearer.
Useful particle references
See p-skeleton-1 (full loading flow) and p-skeleton-2 (skeleton-only layout).
coss Slider
When to use
- Continuous or ranged numeric tuning interactions.
- Volume/brightness/threshold controls with immediate feedback.
Install
npx shadcn@latest add @coss/sliderManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Slider, SliderValue } from "@/components/ui/slider"Minimal pattern
<Slider aria-label="Volume" defaultValue={40} max={100} min={0} />Patterns from coss particles
Key patterns
Slider with label and live value display:
<div className="flex flex-col gap-2">
<div className="flex justify-between text-sm">
<Label>Volume</Label>
<SliderValue />
</div>
<Slider aria-label="Volume" defaultValue={50} min={0} max={100} />
</div>Range slider (two thumbs):
<Slider aria-label="Price range" defaultValue={[20, 80]} min={0} max={100} />More examples
See p-slider-1 through p-slider-5 for label, range, vertical, and form integration patterns.
Common pitfalls
- Using slider for discrete option labels where select/radio is clearer.
- Not exposing current value context in nearby UI text when needed.
- Confusing single-value vs range value shapes in controlled mode.
Useful particle references
- with label and value:
p-slider-2 - range slider:
p-slider-3 - vertical:
p-slider-4 - form integration:
p-slider-5
coss Spinner
When to use
- Indeterminate loading indicator for ongoing work.
- Inline pending state in buttons, forms, and async panels.
Install
npx shadcn@latest add @coss/spinnerManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import { Spinner } from "@/components/ui/spinner"Minimal pattern
<div className="flex items-center gap-2">
<Spinner aria-label="Loading" />
<span className="text-sm text-muted-foreground">Loading data…</span>
</div>Patterns from coss particles
Key patterns
Spinner inside a button:
<Button disabled>
<Spinner aria-hidden="true" />
Loading...
</Button>Standalone spinner with label:
<div className="flex items-center gap-2">
<Spinner aria-label="Loading" />
<span className="text-muted-foreground text-sm">Fetching data...</span>
</div>Prefer button built-in loading UI where available over ad-hoc spinner wrappers.
More examples
See p-button-18 and p-input-12 for spinner-in-button and spinner-in-input-group patterns.
Common pitfalls
- Using spinner without accessible label/context for screen readers.
- Showing spinner with no cancel/retry pathway in long-running operations.
- Using spinner when determinate progress value is available.
Useful particle references
- input group:
p-input-12 - button:
p-button-18 - cross-primitive pending states:
p-button-25,p-autocomplete-12,p-toast-3
coss Switch
When to use
- Binary preference toggles in settings flows.
- Immediate on/off state controls with explicit labels.
When NOT to use
- If the control is a pressable command (not a preference) -> use Toggle instead.
- If you need grouped toggle selection -> use ToggleGroup instead.
- If it's a form agreement (terms/conditions) -> use Checkbox instead.
Install
npx shadcn@latest add @coss/switchManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Switch } from "@/components/ui/switch"Minimal pattern
<Label>
<Switch />
Enable notifications
</Label>Patterns from coss particles
Key patterns
Switch with description text (use id/htmlFor when additional content exists):
const id = useId()
<div className="flex items-center justify-between gap-4">
<div className="flex flex-col gap-1">
<Label htmlFor={id}>Marketing emails</Label>
<p className="text-muted-foreground text-xs">
Receive updates about new products and features.
</p>
</div>
<Switch id={id} />
</div>Disabled switch:
<Label>
<Switch disabled />
Marketing emails
</Label>More examples
- disabled:
p-switch-2 - with description:
p-switch-3 - customizing size:
p-switch-6 - card style:
p-switch-4 - form integration:
p-switch-5
Common pitfalls
- Using switch for multi-option selection that should use radio/toggle-group.
- Omitting visible label or explicit
aria-labelfor icon-only switch controls. - Treating switch as form value without verifying checked-state wiring.
Useful particle references
See p-switch-1 through p-switch-6 for label, disabled, description, card, form, and size patterns.
coss Table
When to use
- Structured tabular datasets.
- Sortable/filterable row and column displays.
Install
npx shadcn@latest add @coss/tableManual deps from docs:
# No extra runtime dependency required for basic table usage.
# For interactive data tables, add TanStack Table:
npm install @tanstack/react-tableCanonical imports
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"Minimal pattern
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Ada Lovelace</TableCell>
</TableRow>
</TableBody>
</Table>Patterns from coss particles
- Semantic baseline: start with
TableHeader/TableBody/TableRow/TableHead/TableCell, then addTableCaptionandTableFooteras needed. - Card variant: set
variant="card"onTablefor rounded, card-like rows and separated borders (p-table-5). Combine withFramefor app-surface framing (p-table-2), withCardFramefor static tables in a card shell (p-table-7), or with TanStack insideCardFramefor selection (p-table-6) or sorting and pagination (p-table-8). - Status-rich rows: combine
Badgeand decorative dots/icons for state columns while keeping text primary. - Interactive data grids: pair coss table parts with TanStack Table (
flexRender, row models, selection state) for sorting/pagination/selection. - No-results state: always render an explicit empty-state row with
colSpanmatching visible columns. - Fixed layout control: use
className="table-fixed"and column width styles when predictable column sizing is required.
Common pitfalls
- Assuming
Tableitself provides sorting/filter/pagination state; these come from your data layer (for example TanStack Table). - Mixing header/body cell semantics (
TableHeadin body rows orTableCellin headers). - Forgetting to align
colSpanwith actual visible columns in footer/empty rows. - Using table patterns where card/list layouts are more suitable on small screens without responsive handling.
- Omitting
aria-labelfor row-selection checkboxes in interactive tables.
Useful particle references
- basic semantic table with caption/footer:
p-table-1 Frame+ card variant:p-table-2- TanStack + checkboxes +
Frame:p-table-3 - TanStack sorting + pagination +
Frame:p-table-4 - card variant only (no shell):
p-table-5 CardFrame+ static table:p-table-7CardFrame+ TanStack + checkboxes:p-table-6CardFrame+ TanStack + sort + pagination:p-table-8
coss Tabs
When to use
- Mutually exclusive content panels in one region.
- Settings/detail screens split into scoped views.
Install
npx shadcn@latest add @coss/tabsManual deps from docs:
# No extra runtime dependency required for this primitive.Canonical imports
import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/ui/tabs"Minimal pattern
<Tabs defaultValue="tab-1">
<TabsList>
<TabsTab value="tab-1">Tab 1</TabsTab>
<TabsTab value="tab-2">Tab 2</TabsTab>
<TabsTab value="tab-3">Tab 3</TabsTab>
</TabsList>
<TabsPanel value="tab-1">Tab 1 content</TabsPanel>
<TabsPanel value="tab-2">Tab 2 content</TabsPanel>
<TabsPanel value="tab-3">Tab 3 content</TabsPanel>
</Tabs>Patterns from coss particles
Key patterns
Controlled tabs with external state:
const [value, setValue] = useState("tab-1")
<Tabs value={value} onValueChange={setValue}>
<TabsList>
<TabsTab value="tab-1">Tab 1</TabsTab>
<TabsTab value="tab-2">Tab 2</TabsTab>
</TabsList>
<TabsPanel value="tab-1">Content 1</TabsPanel>
<TabsPanel value="tab-2">Content 2</TabsPanel>
</Tabs>Underline variant:
<Tabs defaultValue="tab-1" variant="underline">
<TabsList>
<TabsTab value="tab-1">Tab 1</TabsTab>
<TabsTab value="tab-2">Tab 2</TabsTab>
</TabsList>
...
</Tabs>More examples
- underline variant:
p-tabs-2 - vertical orientation:
p-tabs-3 - underline with vertical orientation:
p-tabs-4
Common pitfalls
- Mismatching
TabsTab valueandTabsPanel valuepairs. - Using tabs for workflows that require route-level navigation instead.
- Mounting expensive panel content without considering visibility/performance.
Useful particle references
See p-tabs-1 through p-tabs-4 for variants and orientations. Related: p-toolbar-1, p-card-1.
coss Textarea
When to use
- Multi-line text entry (notes, feedback, descriptions).
- Comment/message inputs where text length is variable.
Install
npx shadcn@latest add @coss/textareaManual deps from docs:
npm install @base-ui/reactCanonical imports
import { Textarea } from "@/components/ui/textarea"Minimal pattern
<Textarea aria-label="Message" placeholder="Write your message" />For form fields, prefer wrapping Textarea with Field + FieldLabel + FieldError so labels, validation, and errors stay semantically linked. Textarea already wraps Base UI Field.Control internally, so it works as a form control directly inside Field (no need to manually use FieldControl + render just to mount a textarea).
Patterns from coss particles
Key patterns
Textarea in a field with label:
<Field name="bio">
<FieldLabel>Bio</FieldLabel>
<Textarea placeholder="Tell us about yourself..." />
<FieldDescription>Max 500 characters.</FieldDescription>
<FieldError />
</Field>Sizes: sm, default, lg on Textarea.
Textarea wraps Base UI Field.Control internally, so it works as a form control directly inside Field.
More examples
See p-textarea-1 through p-textarea-6 for sizes, disabled, label, and form integration patterns.
Common pitfalls
- Using textarea when a constrained single-line input is expected.
- Missing labels/descriptions for required long-form fields.
- Forgetting explicit submit button type handling in textarea forms.
- Using
FieldControl render={<textarea .../>}for basic textarea fields whenTextareaalready provides the correct control integration.
Useful particle references
- small size:
p-textarea-2 - large size:
p-textarea-3 - disabled:
p-textarea-4 - with label:
p-textarea-5 - form integration:
p-textarea-6
coss Toggle Group
When to use
- Grouped pressed-state controls (single or multiple).
- Formatting/action sets needing button-like toggles with shared state.
Install
npx shadcn@latest add @coss/toggle-groupManual deps from docs:
npm install @base-ui/reactCanonical imports
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"Minimal pattern
<ToggleGroup>
<ToggleGroupItem>Bold</ToggleGroupItem>
<ToggleGroupItem>Italic</ToggleGroupItem>
<ToggleGroupItem>Underline</ToggleGroupItem>
</ToggleGroup>Patterns from coss particles
Key patterns
Toggle group with icon buttons:
<ToggleGroup defaultValue={["bold"]}>
<ToggleGroupItem aria-label="Toggle bold" value="bold">
<BoldIcon aria-hidden="true" />
</ToggleGroupItem>
<ToggleGroupItem aria-label="Toggle italic" value="italic">
<ItalicIcon aria-hidden="true" />
</ToggleGroupItem>
<ToggleGroupItem aria-label="Toggle underline" value="underline">
<UnderlineIcon aria-hidden="true" />
</ToggleGroupItem>
</ToggleGroup>Multiple selection (default). For single selection use type="single".
Controlled toggle group:
const [value, setValue] = useState(["bold"])
<ToggleGroup value={value} onValueChange={setValue}>
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
...
</ToggleGroup>More examples
See p-toggle-group-1 through p-toggle-group-9 for sizes, outline, vertical, disabled, multiple, and tooltip patterns.
Common pitfalls
- Using toggle-group when plain buttons (no pressed state) are more appropriate.
- Wrong value shape for mode (
multiplearray vs single selection). - Missing accessible labels on icon-only toggle items.
Useful particle references
- small toggles:
p-toggle-group-2 - large toggles:
p-toggle-group-3 - with outline toggles:
p-toggle-group-4 - vertical:
p-toggle-group-5 - disabled:
p-toggle-group-6 - with disabled toggle:
p-toggle-group-7 - multiple selection:
p-toggle-group-8 - with tooltips:
p-toggle-group-9
Related skills
How it compares
Use coss over generic React UI skills when the project standardizes on the coss registry and Base UI rather than shadcn/Radix defaults.
FAQ
What are coss sources of truth?
Component docs at apps/ui/content/docs/components, particle examples in the registry, and https://coss.com/ui/llms.txt.
How should overlays be composed?
Follow each primitive's documented trigger and content hierarchy; do not mix patterns across dialog, menu, and select APIs.
How are coss components installed?
Use npx shadcn@latest add @coss/<component> or manual install copying docs-listed dependencies and files.
Is Coss safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.