mcpField
S
shadcn-components

shadcn-components

github.com/fusengineDevelopment3449 installsUpdated 2w ago
Repository

About shadcn-components

A component reference skill for teams building with shadcn/ui. It explains API and composition differences across Base UI, Radix, and React Aria, and directs component work to the matching registry source.

Key features

  1. 01Base UI, Radix, and React Aria guidance
  2. 02Primitive-specific API mapping
  3. 03Component availability by base
  4. 04Composition pattern references
  5. 05Registry lookup workflow
  6. 06Form and component examples

Use cases

  1. 01Identifying the primitive used by a project
  2. 02Building a component with the matching API
  3. 03Checking component availability for a base
  4. 04Finding registry source before adding components

MCP support

The skill requires consulting the shadcn MCP to search and view registry components and obtain add commands.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/fusengine/agents --skill shadcn-components

After installing, type/shadcn-componentsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
baseui-components.md
radix-components.md
references/templates/
dialog-example.md

Details

From the project README
Documents component patterns for shadcn/ui on its three bases — Base UI (default since July 2026), Radix and React Aria — API differences, mapping between primitives (Dialog/Select/Tooltip/Accordion/Popover/Menu/Combobox), per-base component availability, and the three composition patterns (`render` for Base UI, `asChild` for Radix, trigger-wrapper children for React Aria).

Requires detecting the project's primitive first (shadcn-detection) and consulting the shadcn MCP for registry source instead of hand-writing component internals.

shadcn Components

Agent Workflow (MANDATORY)

Before component work, spawn agents in parallel, one Agent call each with a name:

  1. fuse-ai-pilot:explore-codebase - Find existing components
  2. fuse-ai-pilot:research-expert - Verify component APIs via Context7
  3. mcp__shadcn__search_items_in_registries - Search available components

After: Run fuse-ai-pilot:sniper for validation.


Overview

FeatureDescription
Base UI primitivesDefault base for new projects since 2026-07-02 (base-* styles, @base-ui/react); init --defaults = Next.js template + nova preset on the base base = base-nova
Radix primitivesOriginal base (2023), still fully supported (radix-* styles, unified radix-ui package); init -b radix
React Aria primitivesThird base since 2026-07-17 (aria-* styles, react-aria-components); init -b aria
Component mappingSame shadcn wrapper names for Base UI and Radix; React Aria wrappers differ (see below)
API differencesrender vs asChild vs trigger wrapper, part naming, data attributes
cn importComponents import cn from the cn package (Sept 2026); lib/utils.ts is export { cn } from "cn"

Get base-specific docs, examples and API links from the CLI: {runner} shadcn@latest docs dialog --base aria (--base base|radix|aria, defaults to the project base). Component pages: /docs/components/{base|radix|aria}/<name>, each with a Composition tree.


Critical Rules

  1. ALWAYS detect primitive before component work (shadcn-detection)
  2. ALWAYS consult MCP before adding any component
  3. NEVER mix Base UI, Radix and React Aria APIs in same component
  4. MATCH composition pattern to detected primitive
  5. USE registry source as truth, not manual code

Architecture

components/ui/
├── dialog.tsx          # Adapted to detected primitive
├── select.tsx
├── accordion.tsx
└── ...

-> See dialog-example.md for complete component


MCP Usage (MANDATORY)

ALWAYS consult shadcn MCP before adding components:

mcp__shadcn__search_items_in_registries -> find component
mcp__shadcn__view_items_in_registries   -> view source
mcp__shadcn__get_add_command_for_items  -> get install command

Component Mapping Table

Primitive parts used inside components/ui/*.tsx (registry *-nova sources, ui.shadcn.com/r/styles/<style>/<name>.json):

ComponentRadix PartBase UI PartReact Aria Part
Dialog contentDialog.ContentDialog.PopupModal > Dialog
Dialog overlayDialog.OverlayDialog.BackdropModalOverlay
SelectSelect.ContentSelect.Positioner + Select.Popup (+ Select.List)Select + Popover > ListBox
TooltipTooltip.ContentTooltip.Positioner + Tooltip.PopupTooltipTrigger > Tooltip
AccordionAccordion.ContentAccordion.PanelDisclosureGroup > Disclosure > DisclosurePanel
PopoverPopover.ContentPopover.Positioner + Popover.PopupDialogTrigger > Popover
MenuDropdownMenu.ContentMenu.Positioner + Menu.PopupMenuTrigger > Popover > Menu
Comboboxnone (uses @base-ui/react Combobox)Combobox.*ComboBox + Popover > ListBox

Wrapper API at call sites (@/components/ui/*):

Wrapper usageBase UIRadixReact Aria
DialogDialog > DialogTrigger + DialogContentsame as Base UIDialogTrigger > Button + Dialog (no DialogContent)
Popover / Tooltip / DropdownMenuX > XTrigger + XContentsameXTrigger > Button + X (e.g. DropdownMenuTrigger > Button + DropdownMenu)
AccordiondefaultValue={["a"]}, multipletype="single" collapsible defaultValue="a", type="multiple"defaultExpandedKeys={["a"]}, allowsMultipleExpanded, items use id
Selectitems prop on Select, SelectItem valueSelectItem valueplaceholder on Select, SelectItem id
Comboboxitems + ComboboxList render functionsame as Base UIComboboxList children, renderEmptyState, ComboboxItem id
Events / stateonClick, disabled, open/onOpenChangesameonPress, isDisabled, isOpen/onOpenChange
Raw data attrsdata-open, data-starting-style, data-sidedata-state="open", data-sidedata-entering/data-exiting, data-placement, data-focused, data-pressed

Shared data-open: / data-closed: / data-checked: Tailwind variants (from shadcn/tailwind.css) match both [data-state=...] and [data-open].

Component Availability per Base

ComponentBase UIRadixReact Aria
Toast (@base-ui/react/toast, toast.add())yes (July 2026)no: use Sonnerno: use Sonner
Sonnerregistry item exists; docs route to Toastyesyes
Menubar, Navigation Menuyesyesno (r/styles/aria-nova/{menubar,navigation-menu}.json → 404)
Questionnaire (styled over @shadcn/react/questionnaire)yesyesyes
MessageScroller, Message, Bubble, Attachment, Marker (chat, June 2026)yesyesyes (docs pages exist)
Blocks (login-01, sidebar, dashboard...)yesyesyes (e.g. r/styles/aria-nova/login-01.json); add picks the project base

Forms (/docs/forms): every guide builds on Field, FieldLabel, FieldDescription, FieldError, FieldGroup with data-invalid on Field and aria-invalid on the control — React Hook Form (Controller + Zod zodResolver), TanStack Form (form.Field render prop + Zod), Formisch (Form + Field, Valibot schema), Next.js (Server Action + useActionState, server-side Zod).

@shadcn/react = unstyled headless primitives (@shadcn/react/questionnaire, @shadcn/react/message-scroller); @shadcn/helpers (/ai-sdk, /tanstack-ai) = scripted useChat conversations for demos/tests, not UI. Typography for rendered markdown: shadcn/typeset (one typeset.css, className="typeset").


Composition Patterns

Radix: asChild
<Dialog.Trigger asChild>
  <Button variant="outline">Open</Button>
</Dialog.Trigger>
Base UI: render
<Dialog.Trigger render={<Button variant="outline" />}>
  Open
</Dialog.Trigger>
React Aria: trigger wrapper (no asChild, no render)
<DialogTrigger>
  <Button variant="outline">Open</Button>
  <Dialog>
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
    </DialogHeader>
  </Dialog>
</DialogTrigger>

Reference Guide

Concepts
TopicReferenceWhen to Consult
Radix APIsradix-components.mdBuilding with Radix primitives
Base UI APIsbaseui-components.mdBuilding with Base UI primitives
React Aria APIsTables above + dialog-example.mdBuilding with React Aria primitives
Templates
TemplateWhen to Use
dialog-example.mdCreating Dialog components

Best Practices

DO
  • Detect primitive FIRST (use shadcn-detection)
  • Consult MCP for component source before editing
  • Follow existing naming conventions in project
  • Use correct composition pattern for detected primitive
DON'T
  • Mix asChild, render and React Aria trigger wrappers in same component
  • Assume Radix (or the new Base UI default) without detection
  • Manually write component internals (use MCP)
  • Skip registry check before adding new components

Comments

Markdown supported