Dialog
A modal dialog that interrupts the user with important content and expects a response.
Usage
Dialog is fully composable: you assemble the portal, overlay, and panel yourself, so your app controls layering and every user-facing string. For a dialog that becomes a drawer on mobile, see Responsive Dialog.
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
} from '@epilot/spark-ui/dialog'<Dialog>
<DialogTrigger
render={
<Button styleVariant="surface" color="neutral">
Open Dialog
</Button>
}
/>
<DialogPortal>
<DialogOverlay />
<DialogContent>
<DialogClose aria-label={t('close')} />
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose
render={
<Button styleVariant="surface" color="neutral">
Cancel
</Button>
}
/>
<Button>Continue</Button>
</DialogFooter>
</DialogContent>
</DialogPortal>
</Dialog>Examples
Controlled Dialog
Use the open and onOpenChange props to control the dialog state programmatically.
const [open, setOpen] = React.useState(false)
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger render={<Button>Open</Button>} />
<DialogPortal>
<DialogOverlay />
<DialogContent>
<DialogHeader>
<DialogTitle>Controlled Dialog</DialogTitle>
<DialogDescription>
This dialog's open state is controlled by React state.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button onClick={() => setOpen(false)}>Close</Button>
</DialogFooter>
</DialogContent>
</DialogPortal>
</Dialog>
)Scrollable with sticky footer
Cap the panel height and give the grid explicit rows: auto header,
minmax(0,1fr) body, auto footer. The body scrolls; header and footer stay
visible.
Close Button
A bare DialogClose placed directly inside DialogContent renders the
ready-made corner X. Pass a translated aria-label from your app; the library
ships no default text. Give it children for a visible text label, or a render
prop to merge into your own element, e.g. a footer Button that closes the
dialog (children would nest a <button> inside the close <button>).
<DialogContent>
<DialogClose aria-label={t('close')} />
{/* ... */}
<DialogFooter>
<DialogClose
render={
<Button styleVariant="surface" color="neutral">
Cancel
</Button>
}
/>
<Button>Confirm</Button>
</DialogFooter>
</DialogContent>API Reference
Built on top of Base UI Dialog. See the Base UI documentation for the full API.