Skip to Content
⭐️ Leave a star →
ComponentsModal

Modal

Compound modal dialog. Renders into a portal, closes on overlay click or Escape key. Supports controlled and uncontrolled state.

Features

Portal rendering outside the document tree.
Closes on Escape key and overlay click.
Can be controlled or uncontrolled.
Renders with role=“dialog” and aria-modal.
data-state reflects open/closed state.

Example

import { useState } from 'react' import { Modal } from '@wire-ui/react' const [open, setOpen] = useState(false) <button onClick={() => setOpen(true)}>Delete Account</button> <Modal.Root open={open} onOpenChange={setOpen}> <Modal.Portal> <Modal.Overlay> <Modal.Content> <h2>Delete Account</h2> <p> Are you sure you want to delete your account? All of your data will be permanently removed. This action cannot be undone. </p> <div> <Modal.Close>Cancel</Modal.Close> <button onClick={() => setOpen(false)}>Delete</button> </div> </Modal.Content> </Modal.Overlay> </Modal.Portal> </Modal.Root>

Styling

Modal sets data-state on both Overlay and Content. Use it to control visibility and add enter/exit animations.

<Modal.Overlay className=" data-[state=open]:opacity-100 data-[state=closed]:opacity-0 transition-opacity " /> <Modal.Content className=" data-[state=open]:scale-100 data-[state=closed]:scale-95 transition-transform " />

Using data attributes

Both Overlay and Content receive data-state with values "open" or "closed".

/* Fade in/out overlay */ [data-state="open"] { opacity: 1; } [data-state="closed"] { opacity: 0; pointer-events: none; } /* Scale content */ [data-state="open"] { transform: scale(1); } [data-state="closed"] { transform: scale(0.95); }

Root props

PropTypeDefaultDescription
openbooleanControlled open state
defaultOpenbooleanfalseInitial state for uncontrolled use
onOpenChange(open: boolean) => voidCalled when open state changes

Data attributes

data-state is set on both Modal.Overlay and Modal.Content:

ValueWhen
"open"Modal is open
"closed"Modal is closed

Behaviour

  • Portal — content is rendered outside the document tree via createPortal
  • Escape key — closes the modal
  • Overlay click — closes the modal
  • Modal.Content — renders with role="dialog" and aria-modal="true"
  • Modal.Close — any button inside that calls onOpenChange(false) on click

Animation

Use data-state with CSS transitions:

[data-state="open"] { animation: fadeIn 150ms ease; } [data-state="closed"] { animation: fadeOut 150ms ease; }

Keyboard Interactions

KeyDescription
EscapeCloses the modal.
TabMoves focus to the next focusable element inside the modal.
Shift+TabMoves focus to the previous focusable element inside the modal.
Last updated on

MIT License © 2026 wire-ui

Modal – Wire UI