In short
Making a dropdown that works with the keyboard, screen readers and focus is surprisingly hard. Radix does that hard part and lets you style it however you want.
A library of unstyled, fully accessible component primitives (dialogs, dropdowns, tooltips) that you style yourself — the foundation many other libraries (like shadcn/ui) are built on.

Think of it like this
A flat with plumbing and wiring done
You get a bare flat where the wiring, plumbing and doors already work. Paint, tiles and furniture are your choice. Radix primitives are that flat. Behaviour and accessibility are fitted, the look is up to you.
Watch it happen
Keyboard user and a Radix Dialog
Enter on Delete post
1/6The user tabs to the trigger and presses Enter.
The big ideas
What you need to know
Unstyled on purpose
Radix ships no visual styles. Use Tailwind, CSS Modules or plain CSS on each part.
Built from parts
A Dialog is Root, Trigger, Portal, Overlay, Content, Title and Close. You arrange the parts yourself.
Accessibility handled
Focus trapping, Escape to close, arrow-key menus and ARIA roles all work out of the box.
Style by state
Parts get data attributes like data-state="open", so you can animate opening and closing in CSS.
See it in code
Walk through the code
1import * as Dialog from "@radix-ui/react-dialog";2export function DeleteDialog() {3 return (4 <Dialog.Root>5 <Dialog.Trigger className="btn">Delete post</Dialog.Trigger>6 <Dialog.Portal>7 <Dialog.Overlay className="fixed inset-0 bg-black/50" />8 <Dialog.Content className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6">9 <Dialog.Title>Delete this post?</Dialog.Title>10 <Dialog.Description>This can't be undone.</Dialog.Description>11 <Dialog.Close className="btn">Cancel</Dialog.Close>12 </Dialog.Content>13 </Dialog.Portal>14 </Dialog.Root>15 );16}1/3Root holds the open state. Trigger is the button that opens it.
Open it and press Tab: focus stays inside. Press Escape: it closes and focus returns to the trigger. You wrote zero lines for that.
Save yourself the pain
Common mistakes
Oops
Leaving out Dialog.Title because the design has no heading.
Do this instead
Screen readers need it. Keep it and hide it visually if needed, for example with a sr-only class.
Oops
Building your own modal with a div and useState to save time.
Do this instead
You'll miss focus trapping and Escape handling. Use a primitive and style it.
Your mission
Keyboard-only test
Quick check
Why do many teams pick Radix instead of building dropdowns and dialogs from scratch?
Go deeper
- 1Build a custom-styled dropdown menu using Radix's primitive components.
- 2Notice how much accessibility (focus trapping, ARIA) comes for free.
- 3Compare 'headless' libraries like Radix to fully-styled ones like Material UI.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.