Radix Primitives Reference

Radix primitives provide behavior for complex interactions while leaving the visual design to your app. Style every Radix part with Tailwind classes so the result matches the app's local design.

Overview

Use native HTML and local Tailwind components for ordinary UI such as buttons, cards, panels, inputs, badges, lists, and page structure.

Reach for direct Radix imports when the interaction itself is complex: dialogs, alert dialogs, dropdown menus, popovers, tabs, selects, accordions, switches, sliders, radio groups, checkboxes, and tooltips.

The generated app runtime depends on the individual Radix React packages, so use direct @radix-ui/react-* imports even when upstream examples show the aggregate radix-ui package.

import * as Dialog from '@radix-ui/react-dialog'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import * as Tabs from '@radix-ui/react-tabs'

Style interactive states with Radix data attributes such as data-state, data-highlighted, data-disabled, data-side, data-align, and data-placeholder.

Dialog and Sheet

A sheet is a Radix dialog styled at the edge of the viewport.

import * as Dialog from '@radix-ui/react-dialog'
import { X } from 'lucide-react'

function DetailsDialog() {
  return (
    <Dialog.Root>
      <Dialog.Trigger className="rounded-full bg-zinc-950 px-4 py-2 text-sm font-medium text-white">
        Open details
      </Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className="fixed inset-0 z-40 bg-black/50" />
        <Dialog.Content className="fixed inset-x-0 bottom-0 z-50 rounded-t-3xl bg-white p-6 text-zinc-950 shadow-2xl md:inset-y-4 md:left-auto md:right-4 md:w-[420px] md:rounded-3xl">
          <div className="flex items-start justify-between gap-4">
            <div>
              <Dialog.Title className="text-lg font-semibold">
                Project details
              </Dialog.Title>
              <Dialog.Description className="mt-1 text-sm text-zinc-500">
                Review ownership, status, and recent activity.
              </Dialog.Description>
            </div>
            <Dialog.Close className="rounded-full p-2 text-zinc-500 hover:bg-zinc-100">
              <X className="h-4 w-4" />
              <span className="sr-only">Close</span>
            </Dialog.Close>
          </div>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  )
}

Use dropdown menus for compact action lists and popovers for lightweight contextual panels.

import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { MoreHorizontal } from 'lucide-react'

<DropdownMenu.Root>
  <DropdownMenu.Trigger className="rounded-full p-2 text-zinc-500 hover:bg-zinc-100">
    <MoreHorizontal className="h-5 w-5" />
    <span className="sr-only">Open menu</span>
  </DropdownMenu.Trigger>
  <DropdownMenu.Portal>
    <DropdownMenu.Content
      align="end"
      sideOffset={8}
      className="z-50 min-w-44 rounded-2xl border border-zinc-200 bg-white p-1 text-sm text-zinc-900 shadow-xl"
    >
      <DropdownMenu.Item className="cursor-pointer rounded-xl px-3 py-2 outline-none data-[highlighted]:bg-zinc-100">
        Rename
      </DropdownMenu.Item>
      <DropdownMenu.Item className="cursor-pointer rounded-xl px-3 py-2 text-red-600 outline-none data-[highlighted]:bg-red-50">
        Delete
      </DropdownMenu.Item>
    </DropdownMenu.Content>
  </DropdownMenu.Portal>
</DropdownMenu.Root>

Tabs and Selects

Use tabs for meaningful view switching. Use Radix Select when native select is not enough for the app's visual design. Select items require Select.ItemText; use position="popper" when you want popover-style side, offset, and trigger-width positioning.

import * as Tabs from '@radix-ui/react-tabs'

<Tabs.Root defaultValue="overview">
  <Tabs.List className="inline-flex rounded-full bg-zinc-100 p-1">
    <Tabs.Trigger
      value="overview"
      className="rounded-full px-4 py-2 text-sm font-medium text-zinc-500 data-[state=active]:bg-white data-[state=active]:text-zinc-950 data-[state=active]:shadow-sm"
    >
      Overview
    </Tabs.Trigger>
    <Tabs.Trigger
      value="history"
      className="rounded-full px-4 py-2 text-sm font-medium text-zinc-500 data-[state=active]:bg-white data-[state=active]:text-zinc-950 data-[state=active]:shadow-sm"
    >
      History
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="overview" className="mt-4">
    Overview content
  </Tabs.Content>
  <Tabs.Content value="history" className="mt-4">
    History content
  </Tabs.Content>
</Tabs.Root>
import * as Select from '@radix-ui/react-select'
import { Check, ChevronDown } from 'lucide-react'

<Select.Root defaultValue="weekly">
  <Select.Trigger
    aria-label="Report cadence"
    className="inline-flex items-center gap-2 rounded-full border border-zinc-200 bg-white px-4 py-2 text-sm font-medium text-zinc-900 data-[placeholder]:text-zinc-400"
  >
    <Select.Value placeholder="Choose cadence" />
    <Select.Icon>
      <ChevronDown className="h-4 w-4" />
    </Select.Icon>
  </Select.Trigger>
  <Select.Portal>
    <Select.Content
      position="popper"
      sideOffset={8}
      className="z-50 w-[var(--radix-select-trigger-width)] overflow-hidden rounded-2xl border border-zinc-200 bg-white p-1 text-sm text-zinc-900 shadow-xl"
    >
      <Select.Viewport>
        <Select.Item
          value="daily"
          className="flex cursor-pointer items-center justify-between rounded-xl px-3 py-2 outline-none data-[highlighted]:bg-zinc-100"
        >
          <Select.ItemText>Daily</Select.ItemText>
          <Select.ItemIndicator>
            <Check className="h-4 w-4" />
          </Select.ItemIndicator>
        </Select.Item>
        <Select.Item
          value="weekly"
          className="flex cursor-pointer items-center justify-between rounded-xl px-3 py-2 outline-none data-[highlighted]:bg-zinc-100"
        >
          <Select.ItemText>Weekly</Select.ItemText>
          <Select.ItemIndicator>
            <Check className="h-4 w-4" />
          </Select.ItemIndicator>
        </Select.Item>
      </Select.Viewport>
    </Select.Content>
  </Select.Portal>
</Select.Root>

Control Primitives

Use these primitives when native controls cannot support the visual treatment.

  • @radix-ui/react-accordion: Root, Item, Header, Trigger, and Content; style open items with data-[state=open].
  • @radix-ui/react-checkbox: Root and Indicator; checked can be true, false, or 'indeterminate'.
  • @radix-ui/react-radio-group: Root, Item, and Indicator.
  • @radix-ui/react-switch: Root and Thumb; style data-[state=checked] and data-[state=unchecked].
  • @radix-ui/react-slider: Root, Track, Range, and one or more Thumb parts; values are number[].
  • @radix-ui/react-tooltip: wrap related tooltips in Tooltip.Provider.