Dialog for forms, details, and other tasks that open above the page. It manages focus, keyboard dismissal, outside clicks, and scrolling. Use AlertDialog when the user must explicitly respond to a decision.
This API is for standalone Twenty UI and the Twenty host application. Front components must use the SDK’s openCommandConfirmationModal instead of rendering Dialog or AlertDialog directly. Native browser dialogs and popovers are also prohibited in the front component renderer.
Usage
Uncontrolled state
Root owns visibility by default. Set defaultOpen for its initial state. Triggers, close controls, Escape, and outside clicks update that state.
Anatomy
Assemble
Portal, Backdrop, Viewport and Popup explicitly. Each DOM part accepts its own native attributes, handlers, className, style, ref and render composition. A ref targets that part’s rendered element. Popup does not create a portal, backdrop or viewport.
Controlled state
Passopen and onOpenChange when the application owns visibility. The callback receives the requested state and Base UI event details, including reason, event, trigger and cancel(). Update state to accept a change, or call eventDetails.cancel() to reject it. onOpenChangeComplete runs when the opening or closing animation finishes.
Composition
Trigger and Close accept render to compose with Button, as shown above. Custom wrappers must forward supplied props and refs. DOM parts preserve Base UI’s state-aware class names, styles and callback render contracts. Header, Body and Footer retain their styled layout and native div composition.
Nest another Dialog.Root inside a popup to open a second dialog. Closing the nested dialog returns focus to its trigger in the parent.
To open one dialog from triggers outside Root, create a handle once with Dialog.createHandle<TPayload>() and pass it to handle on both Root and each Trigger. Trigger payload values are available in Root’s render function. Dialog.Handle and the public DialogHandle type expose the installed handle contract:
Imperative actions take effect only while the associated Root is mounted. Root’s
actionsRef also exposes close() and unmount() for explicit transition control. To control an external closing animation, call eventDetails.preventUnmountOnClose() in onOpenChange, then call the unmount() action when the animation finishes.
Title uses Heading and defaults to an h2 with large type, primary text color, centered alignment, and spacing-4 below it. Use level to change the heading level independently of size, or color to change its text color. Native className, style, refs, and render are forwarded to the heading. Keep a heading element when using render. Description is centered like Title; AlertDialog keeps both left-aligned.
Popup has no padding. Header, Body and Footer provide the inset, so content placed directly in Popup sits against its edges.
Focus, scrolling, and dismissal
Root.modal controls the interaction boundary:
Omit
Backdrop when no visible backdrop is needed. For a nonmodal dialog whose viewport should pass pointer events through to the page, use <Dialog.Viewport data-backdrop-hidden="true">; Popup remains interactive. Omitting the visual backdrop alone does not change Root.modal.
Set Popup.initialFocus or Popup.finalFocus to a ref or callback to choose focus targets; false disables that automatic focus move. Focus callbacks receive the interaction type and retain Base UI’s boolean, element, null and undefined return behavior. Closing normally restores focus to the trigger or previously focused element.
Root.disablePointerDismissal prevents outside clicks from requesting closure. To prevent Escape dismissal, cancel the escape-key change in onOpenChange. Always provide a visible way to close a modal dialog.
Sizes and portals
Popup.size accepts sm, compact, md, lg, xl, and fullscreen, and defaults to md. Long content scrolls within the popup. Width is constrained to the viewport.
Set Portal.container to choose a destination:
Portal.keepMounted retains content and form state while closed. Viewport and Popup carry the provided text direction into an external container; their explicit dir props take precedence. Without a direction provider or explicit dir, they inherit from the destination. See theming and DirectionProvider.
Customize Backdrop and Viewport through their own props. Their native attributes, handlers, refs and render apply to those elements independently of Popup. Backdrop’s forceRender keeps a nested dialog’s backdrop visible when needed. Base UI open and transition state remains available to state-aware styles and render callbacks.
Migration
Wrap existingDialog.Popup content in Dialog.Portal and Dialog.Viewport, and add a sibling Dialog.Backdrop inside Portal. Move container and keepMounted from Popup to Portal. Move former backdrop props onto Backdrop; replace backdrop={false} by omitting Backdrop. Move viewportProps onto Viewport, retaining data-backdrop-hidden="true" when the viewport must pass outside pointer events through. Keep size, initialFocus, finalFocus, native popup attributes and popup refs on Popup. The fused Popup assembly props are removed.
Root, Trigger, Close, Title, Description, Header, Body, Footer and existing handles retain their roles. Public part props, state, actions and event-detail types are exported from twenty-ui/primitives/surfaces.
Props
Dialog.Root
RefObject<DialogRootActions | null>
A ref to imperative actions.
unmount: Ends the closing phase of the dialog after an externally controlled closing animation finishes. CallpreventUnmountOnClose()inonOpenChangefirst, otherwise the dialog completes closing on its own. Whether it leaves the DOM is decided bykeepMountedon the portal.close: Closes the dialog imperatively when called.
ReactNode | PayloadChildRenderFunction<Payload>
Parts or a render function receiving the active trigger payload. Root renders no DOM node.
boolean
default:"false"
Whether the dialog is initially open.To render a controlled dialog, use the
open prop instead.string | null
ID of the trigger that the dialog is associated with.
This is useful in conjunction with the
defaultOpen prop to create an initially open dialog.boolean
default:"false"
Whether to prevent the dialog from closing on outside presses.
For non-modal dialogs, this also prevents the dialog from closing when focus moves outside of it.
DialogHandle<Payload>
Connects detached triggers and imperative dialog actions.
boolean | "trap-focus"
default:"true"
Determines if the dialog enters a modal state when open.
true: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled.false: user interaction with the rest of the document is allowed.'trap-focus': focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled.
modal is true or 'trap-focus', render <Dialog.Close> inside <Dialog.Popup> so
touch screen readers can escape the popup.((open: boolean, eventDetails: DialogRootChangeEventDetails) => void)
Receives the requested state and Base UI event details, including reason, event, trigger and cancel().
((open: boolean) => void)
Event handler called after any animations complete when the dialog is opened or closed.
boolean
Whether the dialog is currently open.
string | null
ID of the trigger that the dialog is associated with.
This is useful in conjunction with the
open prop to create a controlled dialog.
There’s no need to specify this prop when the dialog is uncontrolled (that is, when the open prop is not set).Dialog.Trigger
string | ((state: DialogTriggerState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
DialogHandle<Payload>
A handle to associate the trigger with a dialog.
Can be created with the Dialog.createHandle() method.
string
ID of the trigger. In addition to being forwarded to the rendered element,
it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot
triggerId prop).boolean
default:"true"
Whether the component renders a native
<button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).Payload
A payload to pass to the dialog when it is opened.
((((instance: HTMLButtonElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<HTMLButtonElement | null>) & (((instance: HTMLElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<...>)) | null
Ref to the trigger button, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTriggerState>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.CSSProperties | ((state: DialogTriggerState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Portal
string | ((state: DialogPortalState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null
Portal destination. Omit to use the nearest theme scope, then the parent portal or document body. Explicit null defers mounting; an element, ShadowRoot or ref keeps Base UI resolution.
boolean
default:"false"
Keeps the portal and its content mounted while closed.
Ref<HTMLDivElement>
Ref to the portal div, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogPortalState>
Composes the portal element. Native props and handlers target it.
CSSProperties | ((state: DialogPortalState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Backdrop
string | ((state: DialogBackdropState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
boolean
default:"false"
Renders the backdrop even when this dialog is nested.
Ref<HTMLDivElement>
Ref to the backdrop div, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogBackdropState>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.CSSProperties | ((state: DialogBackdropState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Viewport
ReactNode
Popup and any other content within the positioning viewport.
string | ((state: DialogViewportState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
Ref<HTMLDivElement>
Ref to the viewport div, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogViewportState>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.CSSProperties | ((state: DialogViewportState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Popup
ReactNode
Dialog content. Compose inside Viewport and Portal; Popup does not create those parts or a Backdrop.
string | ((state: DialogPopupState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null)
Controls focus restoration on closing. Accepts a boolean, element ref or callback receiving the interaction type.
boolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | void | HTMLElement | null)
Controls focus on opening. Accepts a boolean, element ref or callback receiving the interaction type.
Ref<HTMLDivElement>
Ref to the popup div, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogPopupState>
Composes the popup element while retaining native props, handlers, dialog semantics and focus behavior.
"compact" | "fullscreen" | "lg" | "md" | "sm" | "xl"
default:"md"
Width of the dialog, or
fullscreen to fill the viewport.CSSProperties | ((state: DialogPopupState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Title
string | ((state: DialogTitleState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
"primary" | "secondary" | "tertiary"
default:"primary"
Theme font color. Defaults to
primary.1 | 2 | 3 | 4 | 5 | 6
default:"2"
Semantic heading level, from
h1 through h6. Does not change the visual size. Defaults to 2.ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTitleState>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render."lg" | "md" | "sm" | "xl" | "xs" | "xxl"
default:"lg"
Visual font size, independent of the heading level. Defaults to
lg.CSSProperties | ((state: DialogTitleState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Description
string | ((state: DialogDescriptionState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
Ref<HTMLParagraphElement>
Ref to the description paragraph, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogDescriptionState>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.CSSProperties | ((state: DialogDescriptionState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Close
string | ((state: DialogCloseState) => string | undefined)
CSS class applied to the element, or a function that
returns a class based on the component’s state.
boolean
default:"true"
Whether the component renders a native
<button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).Ref<HTMLButtonElement>
Ref to the close button, or the element supplied through render.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogCloseState>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.CSSProperties | ((state: DialogCloseState) => CSSProperties | undefined)
Style applied to the element, or a function that
returns a style object based on the component’s state.
Dialog.Header
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.Dialog.Body
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.Dialog.Footer
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.