Dialog
A modal dialog built on Radix UI that traps focus, locks scroll, and dismisses on backdrop click or Escape.
Default
tsx
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogBody,
DialogFooter,
DialogClose,
Button,
CloseButton,
} from "@hummingbirdui/react";
export default function DialogDefault() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Open dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Modal title</DialogTitle>
<DialogClose asChild>
<CloseButton />
</DialogClose>
</DialogHeader>
<DialogBody>
<DialogDescription>
Click the backdrop, press Escape, or use a close button to dismiss
it.
</DialogDescription>
</DialogBody>
<DialogFooter>
<DialogClose asChild>
<Button color="secondary" variant="subtle" className="me-2">
Cancel
</Button>
</DialogClose>
<DialogClose asChild>
<Button>Save changes</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}Centered
Setting centered on DialogContent vertically centers the dialog in the viewport.
tsx
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogBody,
DialogClose,
Button,
CloseButton,
} from "@hummingbirdui/react";
export default function DialogCentered() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Centered dialog</Button>
</DialogTrigger>
<DialogContent centered>
<DialogHeader>
<DialogTitle>Centered</DialogTitle>
<DialogClose asChild>
<CloseButton />
</DialogClose>
</DialogHeader>
<DialogBody>
<DialogDescription>
This dialog is centered vertically in the viewport.
</DialogDescription>
</DialogBody>
</DialogContent>
</Dialog>
);
}Sizes
The size prop sets the dialog width across "sm", "md", "lg", and "xl".
tsx
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogBody,
DialogClose,
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}>
<DialogTrigger asChild>
<Button variant="outline">{size.toUpperCase()} dialog</Button>
</DialogTrigger>
<DialogContent size={size}>
<DialogHeader>
<DialogTitle>{size.toUpperCase()} dialog</DialogTitle>
<DialogClose asChild>
<CloseButton />
</DialogClose>
</DialogHeader>
<DialogBody>
<DialogDescription>
A dialog using <code>size="{size}"</code>.
</DialogDescription>
</DialogBody>
</DialogContent>
</Dialog>
))}
</div>
);
}Scrollable
Setting scrollable keeps the header and footer fixed while a long body scrolls inside the dialog.
tsx
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogBody,
DialogFooter,
DialogClose,
Button,
CloseButton,
} from "@hummingbirdui/react";
export default function DialogScrollable() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Scrollable dialog</Button>
</DialogTrigger>
<DialogContent scrollable centered>
<DialogHeader>
<DialogTitle>Terms of service</DialogTitle>
<DialogClose asChild>
<CloseButton />
</DialogClose>
</DialogHeader>
<DialogBody 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>
</DialogBody>
<DialogFooter>
<DialogClose asChild>
<Button>Got it</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}Fullscreen
Setting fullscreen expands the dialog to fill the entire viewport.
tsx
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogBody,
DialogClose,
Button,
CloseButton,
} from "@hummingbirdui/react";
export default function DialogFullscreen() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Fullscreen dialog</Button>
</DialogTrigger>
<DialogContent fullscreen>
<DialogHeader>
<DialogTitle>Fullscreen</DialogTitle>
<DialogClose asChild>
<CloseButton />
</DialogClose>
</DialogHeader>
<DialogBody>
<DialogDescription>
This dialog fills the entire viewport using{" "}
<code>fullscreen</code>.
</DialogDescription>
</DialogBody>
</DialogContent>
</Dialog>
);
}Controlled
Passing open and onOpenChange to the Dialog root drives its open state externally.
tsx
import * as React from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogBody,
DialogFooter,
DialogClose,
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}>
<DialogContent>
<DialogHeader>
<DialogTitle>Controlled dialog</DialogTitle>
<DialogClose asChild>
<CloseButton />
</DialogClose>
</DialogHeader>
<DialogBody>
<DialogDescription>
Open state is driven by <code>open</code> and{" "}
<code>onOpenChange</code> on the <code>Dialog</code> root.
</DialogDescription>
</DialogBody>
<DialogFooter>
<Button onClick={() => setOpen(false)}>Close</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}API Reference
For detailed usage guidelines, see the Radix UI documentation.
DialogContent
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "sm" | "md" | "lg" | "xl" | "md" | Dialog width. |
| centered | boolean | false | Vertically centers the dialog in the viewport. |
| scrollable | boolean | false | Scrolls the body while the header and footer stay fixed. |
| fullscreen | "false" | "true" | "sm-down" | "md-down" | "lg-down" | "xl-down" | "2xl-down" | false | Expands the dialog to fill the viewport, optionally only below a breakpoint. |
| dialogClassName | string | — | Additional classes merged onto the modal-dialog wrapper. |
| container | HTMLElement | null | — | Portal target forwarded to the underlying Radix Portal. |
| portalProps | object | — | Extra props forwarded to the underlying Radix Portal. |
| overlayProps | object | — | Props forwarded to the modal-backdrop overlay. |
| className | string | — | Additional classes merged with the generated classes. |
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.