Stable in React
Dialog
A popup that opens on top of the entire page.
Install#
One package per framework. Dialog's parts come from it; the anatomy tab at the top shows how they nest.
bun add @▢▢▢▢/react9 parts. The example uses 8 of them; the data does not say which are required.
Dialog.RootGroups all parts of the dialog.Dialog.TriggerA button that opens the dialog.Dialog.PortalA portal element that moves the popup to a different part of the DOM.Dialog.BackdropAn overlay displayed beneath the popup.Dialog.PopupA container for the dialog contents.Dialog.TitleA heading that labels the dialog.Dialog.DescriptionA paragraph with additional information about the dialog.Dialog.CloseA button that closes the dialog.Dialog.ViewportA positioning container for the dialog popup that can be made scrollable. Not in the example.
Examples#
Common ways to put it to work. Each one runs live.
A dialog opens another; the parent styles itself with data-nested-dialog-open and --nested-dialogs.
DialogNested.tsxStyling and accessibility#
The parts ship no styles. Style their states with these attributes; the CSS tab at the top has a sheet. The same CSS works in all five frameworks.
[data-disabled]Present when the trigger is disabled. On Trigger, Close.[data-popup-open]Present when the corresponding dialog is open. On Trigger.[data-open]Present when the dialog is open. On Backdrop, Popup, Viewport.[data-closed]Present when the dialog is closed. On Backdrop, Popup, Viewport.[data-starting-style]Present when the dialog begins animating in. On Backdrop, Popup, Viewport.[data-ending-style]Present when the dialog is animating out. On Backdrop, Popup, Viewport.[data-nested]Present when the dialog is nested within another dialog. On Popup, Viewport.[data-nested-dialog-open]Present when the dialog has other open dialogs nested within it. On Popup, Viewport.--nested-dialogsIndicates how many dialogs are nested within. On Popup.
Keyboard
- EscapeCloses the dialog and returns focus to the trigger On Popup.
- EscapeWith several dialogs open, closes only the one on top On Popup.
- TabShiftTabMoves between the popup's controls; focus wraps inside while
modalis on On Popup.
Set for you
a screen reader says the button opens a dialog and whether it is openTriggeraria-haspopup="dialog",aria-expanded,aria-controlsthe popup is announced as a dialogPopuprole="dialog"the dialog is announced with its heading and its descriptionPopuparia-labelledbyto Title,aria-describedbyto Descriptiona screen reader stays inside the dialogPopuparia-hidden="true"on the rest of the page whilemodalis onthe overlay is not readBackdroprole="presentation"the positioning container is not readViewportrole="presentation"
API reference#
21 props across 9 parts, in React syntax, and className, style, render once for every part. Open a row to try it.
Dialog · all partsclassNameCSS class applied to the element, or a function that
returns a class based on the component's state.string | ((state: State) => string | undefined)styleStyle applied to the element, or a function that
returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>Use it in React#
What differs from the React API. Switch the framework at the top of the page.
@▢▢▢▢/react is the React 19 package. Its parts, props, data attributes and error messages are upstream Base UI's, and upstream's own tests run against it.
- Parts
Each component is its own entry point and exports one namespace named after it.
import { Switch } from '@base-ui-next/react/switch' export function Example() { return ( <Switch.Root> <Switch.Thumb /> </Switch.Root> ) }A part renders the element its API reference names, such as a
<span>forSwitch.Root. - Props and events
Props and callbacks have upstream's names and signatures:
onCheckedChange(checked, details),onOpenChange(open, details),onValueChange(value, details).detailscarriesreason,event,cancel()andallowPropagation(). Native handlers are React's (onClick,onKeyDown), andevent.preventBaseUIHandler()stops a part's own handler. - Styling
classNametakes a string or a function(state) => string;styletakes an object or a function(state) => object. The state'sdata-*attributes are on the element for CSS. renderrendertakes an element (render={<a href="/docs" />}) or a function(props, state) => elementthat spreadspropson what it returns.- Refs
refreaches the part's element. Imperative handles are ref props, as upstream:inputRef, andactionsRef({ validate }on Field and Form,{ unmount, close }on Dialog). - Binding
A part is controlled when its value prop (
checked,open,value) is set, and uncontrolled with thedefaultform (defaultChecked,defaultOpen,defaultValue). React has no two-way binding: pair the value with its change callback. - From @base-ui/reactChange the import from
@base-ui/react/<component>to@▢▢▢▢/react/<component>. - From @base-ui/reactNothing else changes: props, parts, data attributes and errors are the same.