Dialog

The Mosaic Dialog — an opinionated wrapper around the headless @clerk/headless dialog primitives, composed with Mosaic slot recipes. It flattens the required nesting (Root, Portal, Backdrop, Viewport, Popup) into a single component and exposes a close callback through a render-prop children pattern.

Playground

Props

PropTypeDefaultValue
size'md' | 'lg''md'
trigger(props: HTMLAttributes<HTMLElement>) => ReactElement
childrenReactNode | ((ctx: { close: () => void }) => ReactNode)
openboolean
defaultOpenbooleanfalse
onOpenChange(open: boolean) => void
modalbooleantrue
sxStyleRule | (theme) => StyleRule

Usage

import { Button } from '@clerk/ui/mosaic/components/button';
import { Dialog } from '@clerk/ui/mosaic/components/dialog';

<Dialog trigger={props => <Button {...props}>Open dialog</Button>}>
  {({ close }) => (
    <>
      <Dialog.Title>Confirm action</Dialog.Title>
      <Dialog.Description>Are you sure you want to proceed?</Dialog.Description>
      <Button onClick={close}>Cancel</Button>
    </>
  )}
</Dialog>

The trigger render prop receives the interaction props (ARIA attributes, click handler) from Floating UI and should spread them onto whatever element opens the dialog.

children can also be a plain ReactNode when no programmatic close is needed — the dialog can always be dismissed via Escape or clicking the backdrop:

<Dialog trigger={props => <Button {...props}>Open</Button>}>
  <Dialog.Title>Info</Dialog.Title>
  <Dialog.Description>Nothing to confirm here.</Dialog.Description>
</Dialog>

Controlled

const [open, setOpen] = useState(false);

<Dialog
  open={open}
  onOpenChange={setOpen}
  trigger={props => <Button {...props}>Open</Button>}
>
  {({ close }) => (
    <>
      <Dialog.Title>Confirm</Dialog.Title>
      <Button onClick={close}>Cancel</Button>
    </>
  )}
</Dialog>

Sub-parts

PartSlotDescription
Dialog.Titledialog-titleHeading; wired to the popup's aria-labelledby
Dialog.Descriptiondialog-descriptionDescription; wired to the popup's aria-describedby

Styled slots

The Mosaic dialog exposes the following slots that can be styled via appearance.elements:

SlotComponentDescription
dialog-backdropBackdropThemed overlay behind the dialog
dialog-viewportViewportFixed centering container; owns scroll lock
dialog-popupPopupThe dialog surface (role="dialog", focus-trapped)

Styling

Override per slot through appearance.elements — e.g. { 'dialog-popup': { borderRadius: 24 } }. State attributes from the headless layer are also available for CSS targeting:

AttributeApplies ToDescription
data-openTrigger, Backdrop, Viewport, PopupPresent when the dialog is open
data-closedTrigger, Backdrop, Viewport, PopupPresent when closed (during exit)
data-starting-styleBackdrop, Viewport, PopupPresent on the entering frame
data-ending-styleBackdrop, Viewport, PopupPresent during the exit animation