ProComponents, templates & AI tooling
HeroUI
27.7k

Modal

Dialog overlay for focused user interactions and important content

Import

import { Modal } from "@heroui/react";

Usage

Anatomy

Import the Modal component and access all parts using dot notation.

import {Modal, Button} from "@heroui/react";

export default () => (
  <Modal>
    <Button>Open Modal</Button>
    <Modal.Backdrop>
      <Modal.Container>
        <Modal.Dialog>
          <Modal.CloseTrigger /> {/* Optional: Close button */}
          <Modal.Header>
            <Modal.Icon /> {/* Optional: Icon */}
            <Modal.Heading />
          </Modal.Header>
          <Modal.Body />
          <Modal.Footer />
        </Modal.Dialog>
      </Modal.Container>
    </Modal.Backdrop>
  </Modal>
);

Placement

Backdrop Variants

Sizes

Custom Backdrop

Dismiss Behavior

Close Methods

Scroll Behavior

Controlled State

With Form

Custom Trigger

Custom Animations

Custom Portal

Styling

Passing Tailwind CSS classes

import {Modal, Button} from "@heroui/react";

function CustomModal() {
  return (
    <Modal>
      <Button>Open Modal</Button>
      <Modal.Backdrop className="bg-black/80">
        <Modal.Container className="items-start pt-20">
          <Modal.Dialog className="bg-linear-to-br from-purple-500 to-pink-500 text-white">
            <Modal.CloseTrigger />
            <Modal.Header>
              <Modal.Heading>Custom Styled Modal</Modal.Heading>
            </Modal.Header>
            <Modal.Body>
              <p>This modal has custom styling applied via Tailwind classes</p>
            </Modal.Body>
            <Modal.Footer>
              <Button slot="close">Close</Button>
            </Modal.Footer>
          </Modal.Dialog>
        </Modal.Container>
      </Modal.Backdrop>
    </Modal>
  );
}

Customizing the component classes

To customize the Modal component classes, you can use the @layer components directive.


Learn more.

@layer components {
  .modal__backdrop {
    @apply bg-gradient-to-br from-black/50 to-black/70;
  }

  .modal__dialog {
    @apply rounded-2xl border border-white/10 shadow-2xl;
  }

  .modal__header {
    @apply text-center;
  }

  .modal__close-trigger {
    @apply rounded-full bg-white/10 hover:bg-white/20;
  }
}

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The Modal component uses these CSS classes (View source styles):

Base Classes

  • .modal__trigger - Trigger element that opens the modal
  • .modal__backdrop - Overlay backdrop behind the modal
  • .modal__container - Positioning wrapper with placement support
  • .modal__dialog - Modal content container
  • .modal__header - Header section for titles and icons
  • .modal__body - Main content area
  • .modal__footer - Footer section for actions
  • .modal__close-trigger - Close button element

Backdrop Variants

  • .modal__backdrop--opaque - Opaque colored backdrop (default)
  • .modal__backdrop--blur - Blurred backdrop with glass effect
  • .modal__backdrop--transparent - Transparent backdrop (no overlay)

Scroll Variants

  • .modal__container--scroll-outside - Enables scrolling the entire modal
  • .modal__dialog--scroll-inside - Constrains modal height for body scrolling
  • .modal__body--scroll-inside - Makes only the body scrollable
  • .modal__body--scroll-outside - Allows full-page scrolling

Interactive States

The component supports these interactive states:

  • Focus: :focus-visible or [data-focus-visible="true"] - Applied to trigger, dialog, and close button
  • Hover: :hover or [data-hovered="true"] - Applied to close button on hover
  • Active: :active or [data-pressed="true"] - Applied to close button when pressed
  • Entering: [data-entering] - Applied during modal opening animation
  • Exiting: [data-exiting] - Applied during modal closing animation
  • Placement: [data-placement="*"] - Applied based on modal position (auto, top, center, bottom)

API Reference

PropTypeDefaultDescription
childrenReactNode-Trigger and container elements

Modal.Trigger

PropTypeDefaultDescription
childrenReactNode-Custom trigger content
classNamestring-CSS classes

Modal.Backdrop

PropTypeDefaultDescription
variant"opaque" | "blur" | "transparent""opaque"Backdrop overlay style
isDismissablebooleantrueClose on backdrop click
isKeyboardDismissDisabledbooleanfalseDisable ESC key to close
isOpenboolean-Controlled open state
onOpenChange(isOpen: boolean) => void-Open state change handler
classNamestring | (values) => string-Backdrop CSS classes
UNSTABLE_portalContainerHTMLElement-Custom portal container

Modal.Container

PropTypeDefaultDescription
placement"auto" | "center" | "top" | "bottom""auto"Modal position on screen
scroll"inside" | "outside""inside"Scroll behavior
size"xs" | "sm" | "md" | "lg" | "cover" | "full""md"Modal size variant
classNamestring | (values) => string-Container CSS classes

Modal.Dialog

PropTypeDefaultDescription
childrenReactNode | ({close}) => ReactNode-Content or render function
classNamestring | (values) => string-CSS classes
rolestring"dialog"ARIA role
aria-labelstring-Accessibility label
aria-labelledbystring-ID of label element
aria-describedbystring-ID of description element

Modal.Header

PropTypeDefaultDescription
childrenReactNode-Header content
classNamestring-CSS classes

Modal.Body

PropTypeDefaultDescription
childrenReactNode-Body content
classNamestring-CSS classes

Modal.Footer

PropTypeDefaultDescription
childrenReactNode-Footer content
classNamestring-CSS classes

Modal.CloseTrigger

PropTypeDefaultDescription
childrenReactNode-Custom close button
classNamestring | (values) => string-CSS classes

useOverlayState Hook

import {useOverlayState} from "@heroui/react";

const state = useOverlayState({
  defaultOpen: false,
  onOpenChange: (isOpen) => console.log(isOpen),
});

state.isOpen; // Current state
state.open(); // Open modal
state.close(); // Close modal
state.toggle(); // Toggle state
state.setOpen(); // Set state directly

Accessibility

Implements WAI-ARIA Dialog pattern:

  • Focus trap: Focus locked within modal
  • Keyboard: ESC closes (when enabled), Tab cycles elements
  • Screen readers: Proper ARIA attributes
  • Scroll lock: Body scroll disabled when open

On this page