DEV Community

Alex Spinov
Alex Spinov

Posted on

Radix UI Has Free Accessible Components — Here's Why Teams Are Switching

Building accessible UI from scratch is painful. Radix UI gives you unstyled, accessible primitives that just work.

What is Radix UI?

Radix UI is a collection of low-level, unstyled, accessible React components. Unlike Material UI or Chakra, Radix gives you behavior and accessibility — you bring the styles.

Quick Start

bun add @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-popover
Enter fullscreen mode Exit fullscreen mode

Dialog (Modal)

import * as Dialog from "@radix-ui/react-dialog";

export function ConfirmDialog() {
  return (
    <Dialog.Root>
      <Dialog.Trigger asChild>
        <button className="btn">Delete Account</button>
      </Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className="fixed inset-0 bg-black/50" />
        <Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg">
          <Dialog.Title className="text-lg font-bold">
            Are you sure?
          </Dialog.Title>
          <Dialog.Description className="mt-2 text-gray-600">
            This action cannot be undone.
          </Dialog.Description>
          <div className="mt-4 flex gap-3">
            <Dialog.Close asChild>
              <button className="btn-secondary">Cancel</button>
            </Dialog.Close>
            <button className="btn-danger">Yes, delete</button>
          </div>
          <Dialog.Close asChild>
            <button className="absolute top-2 right-2" aria-label="Close">
              X
            </button>
          </Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}
Enter fullscreen mode Exit fullscreen mode

What you get for free: focus trapping, Esc to close, click outside to close, screen reader announcements, proper ARIA attributes.

Dropdown Menu

import * as DropdownMenu from "@radix-ui/react-dropdown-menu";

export function UserMenu() {
  return (
    <DropdownMenu.Root>
      <DropdownMenu.Trigger asChild>
        <button>Options</button>
      </DropdownMenu.Trigger>
      <DropdownMenu.Portal>
        <DropdownMenu.Content className="bg-white shadow-lg rounded-md p-1 min-w-[160px]">
          <DropdownMenu.Item className="px-3 py-2 hover:bg-gray-100 cursor-pointer rounded">
            Profile
          </DropdownMenu.Item>
          <DropdownMenu.Item className="px-3 py-2 hover:bg-gray-100 cursor-pointer rounded">
            Settings
          </DropdownMenu.Item>
          <DropdownMenu.Separator className="h-px bg-gray-200 my-1" />
          <DropdownMenu.Item className="px-3 py-2 hover:bg-red-100 text-red-600 cursor-pointer rounded">
            Logout
          </DropdownMenu.Item>
        </DropdownMenu.Content>
      </DropdownMenu.Portal>
    </DropdownMenu.Root>
  );
}
Enter fullscreen mode Exit fullscreen mode

Tabs

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

export function SettingsTabs() {
  return (
    <Tabs.Root defaultValue="general">
      <Tabs.List className="flex border-b">
        <Tabs.Trigger value="general" className="px-4 py-2 data-[state=active]:border-b-2 data-[state=active]:border-blue-500">
          General
        </Tabs.Trigger>
        <Tabs.Trigger value="security" className="px-4 py-2 data-[state=active]:border-b-2 data-[state=active]:border-blue-500">
          Security
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="general" className="p-4">
        General settings here
      </Tabs.Content>
      <Tabs.Content value="security" className="p-4">
        Security settings here
      </Tabs.Content>
    </Tabs.Root>
  );
}
Enter fullscreen mode Exit fullscreen mode

Why Radix Over Other Libraries

Feature Radix UI Headless UI Material UI Chakra UI
Styled No (you style) No Yes Yes
Accessible Full WAI-ARIA Good Good Good
Bundle Size Tiny (per component) Small Large Medium
Framework Lock React React React React
Customizable 100% High Medium High

The Radix + Tailwind Stack

Radix + Tailwind CSS is the most popular combination. In fact, shadcn/ui is built entirely on Radix primitives styled with Tailwind.

// This is essentially what shadcn/ui does
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out" />
Enter fullscreen mode Exit fullscreen mode

Available Components

Accordion, Alert Dialog, Aspect Ratio, Avatar, Checkbox, Collapsible, Context Menu, Dialog, Dropdown Menu, Form, Hover Card, Label, Menubar, Navigation Menu, Popover, Progress, Radio Group, Scroll Area, Select, Separator, Slider, Switch, Tabs, Toast, Toggle, Toggle Group, Toolbar, Tooltip.

All free. All accessible. All unstyled.


Building data-driven UIs? Check out my web scraping actors on Apify Store — get clean, structured data for your dashboards. For custom solutions, email spinov001@gmail.com.

Top comments (0)