Claude
Skills
Sign in
Back

radix-ui

Included with Lifetime
$97 forever

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.

Design

What this skill does


# Radix UI Expert

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

## Two Products

| 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.

## When This Skill Activates

- Installing or using `radix-ui` or `@radix-ui/react-*` packages
- Building accessible components (dialog, popover, dropdown, accordion)
- Using `asChild` prop for composition
- Animating Radix components (enter/exit transitions)
- Configuring Radix Themes (colors, radius, scaling)
- Questions about WAI-ARIA patterns, keyboard navigation, focus management

## Synergy with Other Frontend Skills

| 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** |

## Live Component Lookup

This skill covers architecture, composition patterns, and the most common components. For any specific component's full API -- spawn a **quick-searcher** agent.

### URL patterns

| 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

## Core Philosophy

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:

1. **Unstyled** - zero CSS shipped, style with anything (Tailwind, CSS Modules, styled-components)
2. **Accessible** - WAI-ARIA design patterns, full keyboard navigation, screen reader tested
3. **Composable** - granular sub-components, `asChild` for element delegation, controlled/uncontrolled

## Installation

```bash
# Unified package (recommended, tree-shakeable)
npm install radix-ui

# Or individual packages
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu
```

## Component Catalog (Primitives)

See [references/primitives-components.md](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) |

## Composition Model

### Sub-component architecture

Every Radix component is split into named parts that you compose:

```tsx
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>
```

### asChild prop

The `asChild` prop delegates rendering to the child element, merging Radix behavior onto your own component:

```tsx
// 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`:
1. **Spread all props** onto the DOM element
2. **Forward ref** using `React.forwardRef` (or ref prop in React 19)

```tsx
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>
```

### Composing multiple primitives

`asChild` nests to combine behaviors:

```tsx
<Tooltip.Trigger asChild>
  <Dialog.Trigger asChild>
    <MyButton>Edit</MyButton>
  </Dialog.Trigger>
</Tooltip.Trigger>
```

### Controlled vs uncontrolled

All stateful components support both patterns:

```tsx
// 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}>
```

## Data Attributes

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 |

### Styling with data attributes

```css
/* 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;
}
```

## Animation Patterns

See [references/patterns.md](references/patterns.md) for detailed animation patterns.

### CSS animations (recommended)

Radix suspends unmounting during CSS animations, enabling exit animations:

```css
@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; }
```

### CSS variables for dynamic sizing

Accordion and Collapsible expose size variables for smooth height animation:

```css
.AccordionContent[data-state="open"] {
  animation: slideDown 300ms ease-out;
}
@keyframes slideDown {
  from { height: 0; }
  to { height: var(--radix-accordion-content-height); }
}
```

### JavaScript animation libraries

Use `forceMount` to prevent Radix from unmounting content, letting your library control the exit:

```tsx
<Dialog.Portal forceMount>
  <AnimatePresence>
    {open && (
      <Dialog.Content forceMount asChild>
        <motion.

Related in Design