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=&quot;{size}&quot;</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

PropTypeDefaultDescription
size"sm" | "md" | "lg" | "xl""md"Dialog width.
centeredbooleanfalseVertically centers the dialog in the viewport.
scrollablebooleanfalseScrolls the body while the header and footer stay fixed.
fullscreen"false" | "true" | "sm-down" | "md-down" | "lg-down" | "xl-down" | "2xl-down"falseExpands the dialog to fill the viewport, optionally only below a breakpoint.
dialogClassNamestring—Additional classes merged onto the modal-dialog wrapper.
containerHTMLElement | null—Portal target forwarded to the underlying Radix Portal.
portalPropsobject—Extra props forwarded to the underlying Radix Portal.
overlayPropsobject—Props forwarded to the modal-backdrop overlay.
classNamestring—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.