A modal window overlaid on the page. Blocks interaction with the rest of the UI until dismissed. Manages focus trap, scroll lock, and Escape-to-close out of the box.
Use for: confirmations, forms that need full attention, message composers, anything where you want everything else to wait.
For non-modal floating panels, use Popover instead. For destructive confirmations specifically, see AlertDialog.
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.Close />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
Dialog.Rootopen / defaultOpen — controlled / uncontrolled open stateonOpenChange(open)modal — default true. Set false for a non-modal dialog (no scroll lock, no focus trap)Dialog.ContentforceMount — keep mounted (animation lib bridge)onOpenAutoFocus(e) — call e.preventDefault() to skip auto-focus on openonCloseAutoFocus(e) — same for closeonEscapeKeyDown(e)onPointerDownOutside(e)onInteractOutside(e) — combined pointer + focus| Key | Behavior |
|---|---|
Esc |
Closes the dialog |
Tab / Shift+Tab |
Cycles focus inside the content (focus is trapped while open) |
import * as Dialog from '@radix-ui/react-dialog';
<Dialog.Root>
<Dialog.Trigger>Send message</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>Send to agent</Dialog.Title>
<Dialog.Description>Message will land in the recipient's mailbox.</Dialog.Description>
<textarea />
<Dialog.Close>Send</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
aria-labelledby (Title) and aria-describedby (Description) automatically<body> is locked while openDialog.Title, screen readers will warn — wrap it in VisuallyHidden if you don't want a visible title@radix-ui/react-dialogA small floating label that appears on hover or keyboard focus. Strictly informational — never put interactive content inside. Tooltips are for naming icon-only controls, expanding abbreviations, surfacing units, etc.
For interactive floating panels, use Popover. For named hover-cards (link previews), use HoverCard.
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger />
<Tooltip.Portal>
<Tooltip.Content>
<Tooltip.Arrow />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
Tooltip.Provider typically wraps your whole app once.
Tooltip.ProviderdelayDuration — ms before tooltip opens after hover (default 700)skipDelayDuration — ms window during which subsequent tooltips open instantly (default 300)disableHoverableContent — disables the brief hover-into-content grace periodTooltip.Rootopen / defaultOpen / onOpenChangedelayDuration — overrides Provider for this RootdisableHoverableContentTooltip.Contentside, sideOffset, align, alignOffset — same Popper props as DropdownMenuavoidCollisions, collisionBoundary, sticky, hideWhenDetachedforceMount| Key | Behavior |
|---|---|
Tab (focus trigger) |
Tooltip opens immediately |
Esc |
Closes the tooltip |
Tooltips also open on hover and close on blur or pointer-leave.
import * as Tooltip from '@radix-ui/react-tooltip';
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<button aria-label="HALT">⏹</button>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content side="top" sideOffset={4}>
Halt all messaging
<Tooltip.Arrow />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
aria-describedby on the triggeraria-label — if your trigger has no visible text, give it an aria-label and a tooltip with the same text (or use Tooltip.Trigger asChild and let the wrapped button carry the label)@radix-ui/react-tooltipA succinct, transient message that appears in a corner viewport and auto-dismisses. Supports actions and swipe-to-dismiss on touch.
Use for: "message sent", "agent went offline", "halt acknowledged", confirmations after async actions. Not for blocking decisions (use Dialog or AlertDialog).
<Toast.Provider>
{/* one or more Toast.Root rendered conditionally */}
<Toast.Root>
<Toast.Title />
<Toast.Description />
<Toast.Action />
<Toast.Close />
</Toast.Root>
<Toast.Viewport />
</Toast.Provider>
The Viewport is the fixed-position container the toasts render into. It's typically placed once at the root of your app.
Toast.Providerduration — default ms a toast stays open (default 5000)label — accessible label for the viewport (default "Notifications")swipeDirection — "right" | "left" | "up" | "down"swipeThreshold — px thresholdToast.Roottype — "foreground" (default, polite) or "background" (assertive)duration — overrides Provider for this ToastdefaultOpen / open / onOpenChangeforceMountToast.ActionaltText — required, screen-reader-only fallback for users who can't reach the F8 viewport in timeToast.Viewporthotkey — keyboard shortcut to focus the viewport (default ["F8"])label| Key | Behavior |
|---|---|
F8 (default hotkey) |
Move focus into the toast viewport |
Tab / Shift+Tab |
Cycle through toasts |
Esc |
Close the focused toast |
import * as Toast from '@radix-ui/react-toast';
<Toast.Provider swipeDirection="right">
<button onClick={() => setOpen(true)}>Send</button>
<Toast.Root open={open} onOpenChange={setOpen}>
<Toast.Title>Message sent</Toast.Title>
<Toast.Description>Delivered to goulard3120</Toast.Description>
<Toast.Action altText="Undo send" asChild>
<button onClick={undo}>Undo</button>
</Toast.Action>
<Toast.Close>×</Toast.Close>
</Toast.Root>
<Toast.Viewport />
</Toast.Provider>
type="foreground" uses aria-live="assertive" (interruptive); "background" uses "polite"altText because screen readers may dismiss the toast before the user can reach the action@radix-ui/react-toastA two-state on/off control. Visually a sliding toggle, semantically a role="switch" checkbox. Use when flipping the switch takes effect immediately (no Save button needed).
For an on/off control that's part of a Save-and-submit form and feels more like a checkbox, use Checkbox. For one-of-N choices, use RadioGroup. For a button that toggles a UI state (bold/italic in a toolbar), use Toggle.
<Switch.Root>
<Switch.Thumb />
</Switch.Root>
Switch.RootdefaultChecked / checked — uncontrolled / controlledonCheckedChange(checked)disabledrequiredname — for form submissionvalue — value submitted when checked is true (default "on")| Key | Behavior |
|---|---|
Tab |
Focuses the switch |
Space / Enter |
Toggles the state |
import * as Switch from '@radix-ui/react-switch';
<label>
HALT mode
<Switch.Root checked={halted} onCheckedChange={setHalted}>
<Switch.Thumb />
</Switch.Root>
</label>
role="switch" with aria-checked reflecting state<label> or an aria-label so screen readers announce what the switch controlsThumb is decorative — the Root is the focusable, labeled control@radix-ui/react-switchA numeric range input. Single thumb for a single value; multiple thumbs for a range. Supports steps, orientation, and inversion.
Use for: volume, opacity, threshold tuning, date or numeric ranges. For discrete one-of-N choice, prefer RadioGroup or a stepper.
<Slider.Root>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb />
</Slider.Root>
For a two-thumb range, render Slider.Thumb twice and pass an array to value / defaultValue.
Slider.RootdefaultValue / value — number array. [50] for single, [20, 80] for rangeonValueChange(values) — fires on every change while draggingonValueCommit(values) — fires only when interaction ends (mouseup, keyboard release)min (default 0) / max (default 100) / step (default 1)orientation — "horizontal" (default) or "vertical"dir — "ltr" / "rtl"disabledinverted — visually swap which side is filledminStepsBetweenThumbs — keeps multi-thumb sliders from crossing| Key | Behavior |
|---|---|
ArrowRight / ArrowUp |
Increment by step |
ArrowLeft / ArrowDown |
Decrement by step |
PageUp / PageDown |
Increment / decrement by larger amount |
Home / End |
Jump to min / max |
import * as Slider from '@radix-ui/react-slider';
<Slider.Root
defaultValue={[5000]}
min={1000}
max={30000}
step={500}
onValueChange={([ms]) => setToastDuration(ms)}
>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb aria-label="Toast duration in ms" />
</Slider.Root>
role="slider" with aria-valuemin, aria-valuemax, aria-valuenowaria-label (or aria-labelledby) on each Slider.Thumb — especially in multi-thumb sliders, label the lower and upper thumbs distinctlyonValueCommit for expensive side effects so you don't fire on every micro-step@radix-ui/react-sliderSwitches between mutually exclusive panels of content rendered in the same place. The active tab determines which panel is shown.
Use for: settings panes, dashboards with multiple views, anything where exactly one of N panels should be visible at a time.
<Tabs.Root>
<Tabs.List>
<Tabs.Trigger value="..." />
</Tabs.List>
<Tabs.Content value="..." />
</Tabs.Root>
Tabs.Rootvalue / defaultValue — controlled / uncontrolled active tab valueonValueChange(value) — fires when active tab changesorientation — "horizontal" (default) or "vertical"activationMode — "automatic" (default, focus-activates) or "manual" (Enter/Space to activate)dir — "ltr" / "rtl"Tabs.Triggervalue — required, must match a Tabs.Content valuedisabledTabs.Contentvalue — requiredforceMount — keep mounted when inactive (useful for animation libs)| Key | Behavior |
|---|---|
Tab |
Focus moves into/out of the tab list |
ArrowRight / ArrowLeft |
Move focus to next/prev trigger (horizontal) |
ArrowDown / ArrowUp |
Same, in vertical orientation |
Home / End |
Jump to first/last trigger |
Enter / Space |
Activate trigger (only in manual mode) |
import * as Tabs from '@radix-ui/react-tabs';
<Tabs.Root defaultValue="services">
<Tabs.List aria-label="localMesh sections">
<Tabs.Trigger value="services">Services</Tabs.Trigger>
<Tabs.Trigger value="agents">Agents</Tabs.Trigger>
<Tabs.Trigger value="messages">Messages</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="services">…service grid…</Tabs.Content>
<Tabs.Content value="agents">…agent list…</Tabs.Content>
<Tabs.Content value="messages">…message stream…</Tabs.Content>
</Tabs.Root>
tablist / tab / tabpanel are wired automaticallyaria-label on Tabs.List if the surrounding context doesn't make the purpose obvious@radix-ui/react-tabsradix-vault · built 2026-05-07 · home