How to build an accessible Modal in React
Built on the native <dialog> element so showModal() provides a real focus trap, top-layer rendering, and inert background for free; role="dialog" plus aria-labelledby/aria-describedby tie the title and description to the dialog, and Escape closes via the platform.
When to use a Modal
- Presenting focused content or a task that must interrupt the current flow
- Confirmations and forms that require the user to act before continuing
- Cases needing a modal backdrop, focus trap, and Escape-to-close from the native <dialog>
When not to use it
- Anchored, non-modal content next to a trigger — use Popover
- A side panel or drawer for secondary content — use Sheet
- A destructive confirmation with a clear yes/no decision — use AlertDialog
Keyboard interactions
Role dialog, verified at WCAG 2.2-AA.
EscapeTabShift+Tab
Common mistakes
Avoid: Rendering <Modal> mounted but driving visibility with CSS display
Prefer: Control visibility with the open prop
The open prop drives showModal()/close() on the native dialog, which manages the top layer, backdrop, and focus trap; hiding with CSS breaks all three
Example
<Modal open={isOpen} onClose={() => setIsOpen(false)} title="Confirm action">
<p>Are you sure?</p>
</Modal>