Dialog
A modal dialog built on Radix UI that traps focus, locks scroll, and dismisses on backdrop click or Escape.
Default
tsx
import { Dialog, Button, CloseButton } from "@hummingbirdui/react";
export default function DialogDefault() {
return (
<Dialog>
<Dialog.Trigger asChild>
<Button variant="outline">Open dialog</Button>
</Dialog.Trigger>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Modal title</Dialog.Title>
<Dialog.Close asChild>
<CloseButton />
</Dialog.Close>
</Dialog.Header>
<Dialog.Body>
<Dialog.Description>
Click the backdrop, press Escape, or use a close button to dismiss
it.
</Dialog.Description>
</Dialog.Body>
<Dialog.Footer>
<Dialog.Close asChild>
<Button color="secondary" variant="subtle" className="me-2">
Cancel
</Button>
</Dialog.Close>
<Dialog.Close asChild>
<Button>Save changes</Button>
</Dialog.Close>
</Dialog.Footer>
</Dialog.Content>
</Dialog>
);
}Centered
Setting centered on Dialog.Content vertically centers the dialog in the viewport.
tsx
import { Dialog, Button, CloseButton } from "@hummingbirdui/react";
export default function DialogCentered() {
return (
<Dialog>
<Dialog.Trigger asChild>
<Button variant="outline">Centered dialog</Button>
</Dialog.Trigger>
<Dialog.Content centered>
<Dialog.Header>
<Dialog.Title>Centered</Dialog.Title>
<Dialog.Close asChild>
<CloseButton />
</Dialog.Close>
</Dialog.Header>
<Dialog.Body>
<Dialog.Description>
This dialog is centered vertically in the viewport.
</Dialog.Description>
</Dialog.Body>
</Dialog.Content>
</Dialog>
);
}Sizes
The size prop sets the dialog width across "sm", "md", "lg", and "xl".
tsx
import { Dialog, Button, CloseButton } from "@hummingbirdui/react";
const sizes = ["sm", "md", "lg", "xl"] as const;
export default function DialogSizes() {
return (
<div className="flex flex-wrap gap-2 justify-center">
{sizes.map((size) => (
<Dialog key={size}>
<Dialog.Trigger asChild>
<Button variant="outline">{size.toUpperCase()} dialog</Button>
</Dialog.Trigger>
<Dialog.Content size={size}>
<Dialog.Header>
<Dialog.Title>{size.toUpperCase()} dialog</Dialog.Title>
<Dialog.Close asChild>
<CloseButton />
</Dialog.Close>
</Dialog.Header>
<Dialog.Body>
<Dialog.Description>
A dialog using <code>size="{size}"</code>.
</Dialog.Description>
</Dialog.Body>
</Dialog.Content>
</Dialog>
))}
</div>
);
}Scrollable
Setting scrollable keeps the header and footer fixed while a long body scrolls inside the dialog.
tsx
import { Dialog, Button, CloseButton } from "@hummingbirdui/react";
export default function DialogScrollable() {
return (
<Dialog>
<Dialog.Trigger asChild>
<Button variant="outline">Scrollable dialog</Button>
</Dialog.Trigger>
<Dialog.Content scrollable centered>
<Dialog.Header>
<Dialog.Title>Terms of service</Dialog.Title>
<Dialog.Close asChild>
<CloseButton />
</Dialog.Close>
</Dialog.Header>
<Dialog.Body className="max-h-72">
<p>Scroll to read all of the content below.</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum
nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi.
Nulla quis sem at nibh elementum imperdiet.
</p>
<p>
Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue
semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla.
</p>
<p>
Class aptent taciti sociosqu ad litora torquent per conubia nostra,
per inceptos himenaeos. Curabitur sodales ligula in libero.
</p>
<p>
Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh.
Aenean quam. In scelerisque sem at dolor. Maecenas mattis.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.Close asChild>
<Button>Got it</Button>
</Dialog.Close>
</Dialog.Footer>
</Dialog.Content>
</Dialog>
);
}Fullscreen
Setting fullscreen expands the dialog to fill the entire viewport.
tsx
import { Dialog, Button, CloseButton } from "@hummingbirdui/react";
export default function DialogFullscreen() {
return (
<Dialog>
<Dialog.Trigger asChild>
<Button variant="outline">Fullscreen dialog</Button>
</Dialog.Trigger>
<Dialog.Content fullscreen>
<Dialog.Header>
<Dialog.Title>Fullscreen</Dialog.Title>
<Dialog.Close asChild>
<CloseButton />
</Dialog.Close>
</Dialog.Header>
<Dialog.Body>
<Dialog.Description>
This dialog fills the entire viewport using <code>fullscreen</code>.
</Dialog.Description>
</Dialog.Body>
</Dialog.Content>
</Dialog>
);
}Controlled
Passing open and onOpenChange to the Dialog root drives its open state externally.
tsx
import * as React from "react";
import { Dialog, Button, CloseButton } from "@hummingbirdui/react";
export default function DialogControlled() {
const [open, setOpen] = React.useState(false);
return (
<>
<Button onClick={() => setOpen(true)} variant="outline">
Open controlled dialog
</Button>
<Dialog open={open} onOpenChange={setOpen}>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Controlled dialog</Dialog.Title>
<Dialog.Close asChild>
<CloseButton />
</Dialog.Close>
</Dialog.Header>
<Dialog.Body>
<Dialog.Description>
Open state is driven by <code>open</code> and{" "}
<code>onOpenChange</code> on the <code>Dialog</code> root.
</Dialog.Description>
</Dialog.Body>
<Dialog.Footer>
<Button onClick={() => setOpen(false)}>Close</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog>
</>
);
}API Reference
Built on the Radix UI Dialog primitive. Each part forwards all props to its Radix counterpart, except Dialog.Header, Dialog.Body, and Dialog.Footer, which are Hummingbird-specific layout parts rendered as plain div elements.
Dialog
Contains all the parts of a dialog.
| Prop | Type | Default |
|---|---|---|
defaultOpen | boolean | — |
open | boolean | — |
onOpenChange | function | — |
modal | boolean | true |
Dialog.Trigger
The button that opens the dialog.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "open" | "closed" |
Dialog.Portal
When used, portals your overlay and content parts into the body. Dialog.Content renders this part automatically, so you rarely need to use it directly.
| Prop | Type | Default |
|---|---|---|
forceMount | boolean | — |
container | HTMLElement | document.body |
Dialog.Overlay
A layer that covers the inert portion of the view when the dialog is open. Dialog.Content renders this part automatically; use its overlayProps prop to customize it.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
forceMount | boolean | — |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "open" | "closed" |
Dialog.Content
Contains content to be rendered in the open dialog. Always renders its own Dialog.Portal and Dialog.Overlay, and wraps the content in the modal and modal-dialog elements.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
forceMount | boolean | — |
onOpenAutoFocus | function | — |
onCloseAutoFocus | function | — |
onEscapeKeyDown | function | — |
onPointerDownOutside | function | — |
onInteractOutside | function | — |
size | enum | "md" |
centered | boolean | false |
scrollable | boolean | false |
fullscreen | enum | false |
dialogClassName | string | — |
container | HTMLElement | document.body |
portalProps | object | — |
overlayProps | object | — |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "open" | "closed" |
Dialog.Header
Hummingbird-specific layout part. Renders a div with the modal-header class for the top area of the dialog.
Dialog.Title
An accessible title to be announced when the dialog is opened. Renders an h6 element by default.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
className | string | — |
Dialog.Description
An optional accessible description to be announced when the dialog is opened.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
className | string | — |
Dialog.Body
Hummingbird-specific layout part. Renders a div with the modal-body class for the main content of the dialog.
Dialog.Footer
Hummingbird-specific layout part. Renders a div with the modal-footer class, typically containing action buttons.
Dialog.Close
The button that closes the dialog.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
className | string | — |
Styling
Hummingbird React dialog is styled entirely through Hummingbird's utility classes and CSS variables.
- See the full list of available dialog classes in the Class overview.
- Visit the CSS Variables documentation to explore all available variables.