Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

Modal

  • Stable
  • WCAG 2.2 evidence
  • RTL

A modal window for a task that needs the user's full attention, such as a short form. Built on React Aria ModalOverlay + Modal + Dialog: a role="dialog" named by its title and described by its subtitle; focus moves inside on open, Tab stays inside (the rest of the page is inert and its scrolling is locked), Escape or the close button closes it, and focus returns to the trigger (WCAG 2.1.1, 2.1.2, 2.4.3, 4.1.2). The body scrolls between a fixed header and footer, and becomes focusable when it overflows; dividers appear while it is scrolled. Below 768 px it docks to the bottom of the screen (1.4.10). Motion only runs when allowed (2.3.3). Consumer duties: a title that states the task and actions that name the outcome; error handling inside the form (3.3.1, 3.3.4). For a quick confirmation use Dialog; for content people compare with the page use Drawer.

import { Modal } from "@nexera-ui/react";
Loading example…
9
examples
18
props
5
live controls
1
platform
11
WCAG criteria
14
blocks use it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
title
children
size
isDismissable
defaultOpen
Generated code
import { Modal } from "@nexera-ui/react";

<Modal />

Examples 8

The same examples as Storybook, rendered live. Open Code to copy one.

Medium

Figma Size=md (560 px).

Loading example…

Large

Figma Size=lg (720 px).

Loading example…

Fullscreen

Figma Size=Fullscreen: fills the viewport; the body scrolls between the header and the footer.

Loading example…

With footer note

Figma Show footer note: a step indicator at the start of the footer.

Loading example…

Long content

Figma Scroll=Scrolled: the body is longer than the viewport allows, so it scrolls (and joins the tab order) while the header and the actions stay in place; dividers appear while there is content above or below.

Loading example…

Controlled

Opened from the page's own state instead of a trigger (isOpen + onOpenChange), for example after a table action.

Loading example…

Right to left

Right-to-left: the close button moves to the left, actions to the left of the footer.

Loading example…

Multi step invite

Loading example…

Props 18

Press "Try it" on a card to load that prop into the playground.

18 props shown

title*Nexera
ReactNode

Title: a level 2 heading that names the dialog (aria-labelledby). State the task ("Add employee"); it wraps instead of truncating.

Default –
subtitleNexera
ReactNode

Supporting line under the title. Also the dialog's description.

Default –
childrenNexera
ReactNode

The body: a form, a list, text. It scrolls between the header and the footer when it is taller than the viewport allows.

Default –
footerNoteNexera
ReactNode

Short note at the start of the footer, such as "Step 1 of 3".

Default –
primaryActionNexera
ReactNode

Main action at the end of the footer: <Button size="md">. Give it slot="close" to close the modal when pressed, or close it yourself through isOpen when the task succeeds.

Default –
secondaryActionNexera
ReactNode

Action before it: usually <Button variant="secondary" size="md" slot="close">Cancel</Button>.

Default –
sizeNexera
"sm" | "md" | "lg" | "fullscreen"

Width: 400 / 560 / 720 px, or the whole viewport. Below 768 px every size except fullscreen becomes a full-width bottom sheet.

Default sm
closeLabelNexera
string

Accessible name of the close button. Translate it for your locale.

Default Close
isDismissableNexera
boolean

Whether a click on the scrim closes the modal. Off by default: a modal holds a task, and a stray click must not throw away what was typed. Escape and the close button always close it unless isKeyboardDismissDisabled.

Default false
idNexera
string

Id of the surface element.

Default –
classNameNexera
string

Extra classes for the surface, merged last so they win over the defaults.

Default –
styleNexera
CSSProperties

Inline style for the surface.

Default –
triggerNexera
ReactElement<unknown, string | JSXElementConstructor<any>>

The element that opens the overlay, usually a Nexera Button. It toggles the overlay when pressed and gets focus back when the overlay closes. Leave it out to open the overlay from your own state (isOpen + onOpenChange).

Default –
isOpenNexera
boolean

Whether the overlay is open (controlled). Use with onOpenChange.

Default –
defaultOpenNexera
boolean

Whether the overlay is open on first render (uncontrolled).

Default false
onOpenChangeNexera
(isOpen: boolean) => void

Called when the overlay opens or closes (Escape, the close button, a slot="close" action, a click outside).

Default –
shouldCloseOnInteractOutsideReact Aria
(element: Element) => boolean

When user interacts with the argument element outside of the overlay ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the overlay. By default, onClose will always be called on interaction outside the overlay ref.

Default –
isKeyboardDismissDisabledReact Aria
boolean

Whether pressing the escape key to close the modal should be disabled.

Default false

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

6 direct · 5 supporting
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.3.2Meaningful SequenceLevel A · tested directly
  • 1.4.4Resize TextLevel AA · supporting test
  • 1.4.10ReflowLevel AA · supporting test
  • 1.4.12Text SpacingLevel AA · supporting test
  • 2.1.1KeyboardLevel A · tested directly
  • 2.1.2No Keyboard TrapLevel A · tested directly
  • 2.3.3Animation from InteractionsLevel AAA · supporting test
  • 2.4.3Focus OrderLevel A · tested directly
  • 2.4.7Focus VisibleLevel AA · supporting test
  • 4.1.2Name, Role, ValueLevel A · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

  • data-divider
  • data-hovered
  • data-pressed
Usage
<Modal className="data-divider:opacity-90 shadow-sm" />

Used in blocks

Related components