plugins/frontend/skills/radix-ui/SKILL.md
Expert guidance for building with Radix UI -- Primitives (unstyled accessible components) and Themes (pre-styled design system). Covers composition patterns, asChild prop, accessibility, animation, theming, color system, and keyboard navigation. Trigger when working with Radix components, @radix-ui packages, or building accessible UI primitives. Also trigger on mentions of "radix", "radix-ui", "radix primitives", "radix themes", "@radix-ui/react-*", or the unified "radix-ui" package. TRIGGER WHEN: working with Radix components, @radix-ui packages, or building accessible UI primitives DO NOT TRIGGER WHEN: the task is outside the specific scope of this component.
npx skillsauth add acaprino/alfio-claude-plugins radix-uiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Guidance for building accessible, composable UIs with Radix UI. Covers both Primitives (unstyled, headless) and Themes (pre-styled design system).
Docs: https://www.radix-ui.com
| Product | What it is | Install | Use when |
|---------|-----------|---------|----------|
| Primitives | Unstyled, accessible component primitives | npm i radix-ui | Building custom design systems, need full style control |
| Themes | Pre-styled component library built on Primitives | npm i @radix-ui/themes | Want production-ready styled components out of the box |
shadcn/ui is built on top of Radix Primitives. If working with shadcn, route to the shadcn-ui skill instead.
radix-ui or @radix-ui/react-* packagesasChild prop for composition| Need | Route to | |------|----------| | shadcn/ui components (Radix + Tailwind, pre-composed) | shadcn-ui | | CSS architecture, modern CSS features | frontend-design | | Page layout composition, grid systems | frontend-layout agent | | Animations, micro-interactions, visual polish | frontend-design agent | | Distinctive visual identity | frontend-css skill | | daisyUI components (different library, class-based) | daisyui |
This skill covers architecture, composition patterns, and the most common components. For any specific component's full API -- spawn a quick-searcher agent.
| Resource | URL pattern |
|----------|-------------|
| Primitives component | https://www.radix-ui.com/primitives/docs/components/{name} |
| Primitives guides | https://www.radix-ui.com/primitives/docs/guides/{topic} |
| Themes component | https://www.radix-ui.com/themes/docs/components/{name} |
| Themes overview | https://www.radix-ui.com/themes/docs/overview/{topic} |
| Themes theming | https://www.radix-ui.com/themes/docs/theme/{topic} |
| Colors reference | https://www.radix-ui.com/colors |
Radix Primitives are unstyled, accessible UI components. They handle the hard parts (WAI-ARIA compliance, keyboard navigation, focus management, screen reader support) while you own all styling. Three key principles:
asChild for element delegation, controlled/uncontrolled# Unified package (recommended, tree-shakeable)
npm install radix-ui
# Or individual packages
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu
See references/primitives-components.md for detailed sub-component APIs.
| Category | Components | |----------|------------| | Overlay | Dialog, Alert Dialog, Popover, Hover Card, Tooltip | | Menu | Dropdown Menu, Context Menu, Menubar | | Navigation | Navigation Menu, Tabs | | Form | Checkbox, Radio Group, Select, Slider, Switch, Toggle, Toggle Group, Form | | Disclosure | Accordion, Collapsible | | Media | Avatar, Aspect Ratio, Progress | | Layout | Scroll Area, Separator, Toolbar | | Utility | Label, Portal, Slot, Visually Hidden, Direction Provider | | Deprecated | Toast (use Sonner instead) |
Every Radix component is split into named parts that you compose:
import * as Dialog from "radix-ui/components/dialog"
<Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/50" />
<Dialog.Content className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg">
<Dialog.Title>Edit Profile</Dialog.Title>
<Dialog.Description>Make changes to your profile.</Dialog.Description>
{/* form content */}
<Dialog.Close className="absolute right-4 top-4">X</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
The asChild prop delegates rendering to the child element, merging Radix behavior onto your own component:
// Default: Radix renders a <button>
<Dialog.Trigger>Open</Dialog.Trigger>
// asChild: Radix merges onto YOUR element
<Dialog.Trigger asChild>
<Link href="/settings">Open Settings</Link>
</Dialog.Trigger>
Requirements for custom components with asChild:
React.forwardRef (or ref prop in React 19)const MyButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ children, ...props }, ref) => (
<button ref={ref} {...props} className="my-button">
{children}
</button>
)
)
<Dialog.Trigger asChild>
<MyButton>Open</MyButton>
</Dialog.Trigger>
asChild nests to combine behaviors:
<Tooltip.Trigger asChild>
<Dialog.Trigger asChild>
<MyButton>Edit</MyButton>
</Dialog.Trigger>
</Tooltip.Trigger>
All stateful components support both patterns:
// Uncontrolled (default) - component manages its own state
<Accordion.Root type="single" defaultValue="item-1">
// Controlled - you manage state
const [value, setValue] = useState("item-1")
<Accordion.Root type="single" value={value} onValueChange={setValue}>
Radix exposes state via data-* attributes for CSS styling:
| Attribute | Values | Used for |
|-----------|--------|----------|
| [data-state] | "open" / "closed" | Overlays, disclosure |
| [data-state] | "checked" / "unchecked" / "indeterminate" | Checkboxes, switches |
| [data-state] | "active" / "inactive" | Tabs, toggles |
| [data-disabled] | present/absent | Disabled elements |
| [data-orientation] | "vertical" / "horizontal" | Accordion, tabs, separator |
| [data-highlighted] | present/absent | Menu items (keyboard focus) |
| [data-side] | "top" / "right" / "bottom" / "left" | Positioned content |
| [data-align] | "start" / "center" / "end" | Positioned content |
/* Tailwind */
<Accordion.Content className="data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp">
/* Plain CSS */
.AccordionContent[data-state="open"] {
animation: slideDown 300ms ease-out;
}
.AccordionContent[data-state="closed"] {
animation: slideUp 300ms ease-in;
}
See references/patterns.md for detailed animation patterns.
Radix suspends unmounting during CSS animations, enabling exit animations:
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.DialogOverlay[data-state="open"] { animation: fadeIn 200ms ease-out; }
.DialogOverlay[data-state="closed"] { animation: fadeOut 200ms ease-in; }
Accordion and Collapsible expose size variables for smooth height animation:
.AccordionContent[data-state="open"] {
animation: slideDown 300ms ease-out;
}
@keyframes slideDown {
from { height: 0; }
to { height: var(--radix-accordion-content-height); }
}
Use forceMount to prevent Radix from unmounting content, letting your library control the exit:
<Dialog.Portal forceMount>
<AnimatePresence>
{open && (
<Dialog.Content forceMount asChild>
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
Content
</motion.div>
</Dialog.Content>
)}
</AnimatePresence>
</Dialog.Portal>
All Radix components implement WAI-ARIA keyboard patterns:
| Component | Keys |
|-----------|------|
| Dialog | Esc close, Tab trap focus |
| Dropdown Menu | Arrow navigate, Enter/Space select, Esc close |
| Accordion | Arrow navigate triggers, Enter/Space toggle, Home/End |
| Tabs | Arrow switch tabs, Tab move to panel |
| Select | Arrow navigate, Enter/Space select |
| Slider | Arrow adjust, Home/End min/max |
| Radio Group | Arrow navigate, Space select |
Radix handles automatically:
role, aria-expanded, aria-controls, aria-labelledby)dir prop / DirectionProviderWhat you must provide:
Title and Description for dialogs/alert dialogs (or use VisuallyHidden)aria-label for icon-only triggersPre-styled component library with built-in theming. Uses Radix Primitives internally but ships with styles, a color system, and layout primitives.
npm install @radix-ui/themes
// app/layout.tsx or main entry
import "@radix-ui/themes/styles.css"
import { Theme } from "@radix-ui/themes"
export default function Layout({ children }) {
return (
<Theme accentColor="indigo" grayColor="slate" radius="medium" scaling="100%">
{children}
</Theme>
)
}
<Theme
accentColor="crimson" // brand color (24 options)
grayColor="sand" // neutral tones (6 options)
radius="large" // border radius (none | small | medium | large | full)
scaling="95%" // global size scale
appearance="dark" // light | dark | inherit
panelBackground="translucent" // solid | translucent
>
import { ThemePanel } from "@radix-ui/themes"
<ThemePanel /> // interactive UI for previewing theme changes
See references/themes-colors.md for the full color reference.
Each color has 12 steps from subtle backgrounds to high-contrast text:
| Steps | Purpose | Example variable |
|-------|---------|-----------------|
| 1-2 | Backgrounds | var(--accent-1), var(--accent-2) |
| 3-5 | Interactive states | var(--accent-3) hover, var(--accent-4) active |
| 6-8 | Borders | var(--accent-6) subtle, var(--accent-8) strong |
| 9-10 | Solid fills | var(--accent-9) primary, var(--accent-10) hover |
| 11-12 | Text | var(--accent-11) low contrast, var(--accent-12) high |
Gray, Gold, Bronze, Brown, Yellow, Amber, Orange, Tomato, Red, Ruby, Crimson, Pink, Plum, Purple, Violet, Iris, Indigo, Blue, Cyan, Teal, Jade, Green, Grass, Lime, Mint, Sky.
Gray, Mauve, Slate, Sage, Olive, Sand. Auto-paired with accent but overridable.
var(--accent-surface) - translucent accent for surface backgroundsvar(--accent-indicator) - for selection indicatorsvar(--accent-track) - for slider/progress tracksvar(--accent-contrast) - guaranteed readable text on accent-9var(--color-background) - page backgroundvar(--color-overlay) - overlay/backdrop<Button color="red">Delete</Button> // overrides theme accent for this button
<Badge color="green" highContrast>Active</Badge>
| Category | Components | |----------|------------| | Layout | Box, Flex, Grid, Section, Container | | Typography | Text, Heading, Code, Quote, Em, Strong, Kbd | | Form | Button, IconButton, TextField, TextArea, Select, Checkbox, Radio Group, Switch, Slider, SegmentedControl | | Overlay | Dialog, Alert Dialog, Popover, Hover Card, Tooltip, Context Menu, Dropdown Menu | | Data Display | Table, Avatar, Badge, Callout, Card, Data List, Inset, Separator, Skeleton | | Feedback | Progress, Spinner | | Navigation | Tabs, Tab Nav, Link |
Most Themes components share:
<Button
size="1" | "2" | "3" | "4" // numeric scale
variant="solid" | "soft" | "outline" | "ghost" | "surface"
color="indigo" // override accent
highContrast={true} // enhanced visibility
radius="full" // override theme radius
loading={true} // loading state
asChild // compose onto child
/>
See references/patterns.md for detailed patterns.
VisuallyHidden if not visible)asChild for routing -- compose Trigger onto <Link> or router componentsforceMount needed)[data-state], [data-highlighted] are stable APIDialog.Overlay, Dialog.Portal exist for a reasonasChilddevelopment
Unified web frontend knowledge base covering CSS architecture, UX psychology, UI components, distinctive aesthetics, and interface design generation. TRIGGER WHEN: working on web styling, design systems, component decisions, responsive strategy, distinctive frontend aesthetics, or exploring multiple interface designs. DO NOT TRIGGER WHEN: the task is purely backend or unrelated to web frontend.
development
Coordinate parallel code reviews across multiple quality dimensions with finding deduplication, severity calibration, and consolidated reporting. Use this skill when organizing multi-reviewer code reviews, calibrating finding severity, or consolidating review results.
tools
Knowledge base for the codebase-mapper plugin. Provides writing guidelines, tone rules, and diagram conventions for generating human-readable project guides. Referenced by all codebase-mapper agents during document generation. TRIGGER WHEN: referenced by codebase-mapper pipeline agents (codebase-explorer, overview-writer, tech-writer, flow-writer, onboarding-writer, ops-writer, config-writer, guide-reviewer) during document generation. DO NOT TRIGGER WHEN: outside the /map-codebase pipeline (general documentation work should use docs:readme-craft or codebase-mapper:docs-create).
tools
Progressive Web App knowledge base for 2025-2026: Web App Manifest, Service Workers (Workbox 7, Serwist), Web Push (VAPID, RFC 8030/8291/8292, Declarative Push for Safari 18.4+), install flows (beforeinstallprompt, Window Controls Overlay), OPFS storage, Project Fugu, Core Web Vitals (INP < 200ms), security (HTTPS, CSP, COOP/COEP), and distribution (Bubblewrap, PWA Builder MSIX, Capacitor). TRIGGER WHEN: building, auditing, or debugging PWAs, including manifest, service worker, Web Push, install flow, OPFS, Background Sync, Wake Lock, vite-plugin-pwa, Next.js Serwist, @angular/pwa, @vite-pwa/nuxt, Bubblewrap, TWA, PWA Builder, or Capacitor wrapping. DO NOT TRIGGER WHEN: the task is generic frontend styling (use frontend), React performance (use react-development:review-react), cross-platform security unrelated to PWA (use platform-engineering), Tauri or Electron wrappers (use tauri-development), or GA4 / analytics (use digital-marketing).