modal
Display popup content that requires attention or provides additional information.
default
sticky
single button
disabled actions
inset
focus an input on open
mobile sheet with inputs
toasts and focus trap
best practices
When to use
- Use
Modalwhen a decision must block the rest of the page. For persistent associated context where the underlying page stays readable, useSheeton desktop orDraweron mobile. - Confirm destructive actions in a
Modal.DrawerandSheetdon't fully dim the page, so they read as too soft for a delete or revoke. - Skip
Modalfor routine create flows that have a dedicated page; route to the page instead.
Behavior
- Default focus to
Cancelon any destructiveModal. Enter must never trigger the destructive action without a typed confirmation. - Allow Escape and outside-click to dismiss non-destructive modals; gate dismissal on destructive ones with unsaved input.
- Trap focus inside the
Modalwhile it's open and return focus to the trigger after close. Restore body scroll on the same tick the modal unmounts. - For high-stakes destructive actions, gate the primary button on a typed match of the resource name.
Content
Modal.Titleis a Title Case statement, never a question.Transfer Projectis correct;Transfer Project?is wrong.- Body copy is sentence case, one to three sentences. State the consequence first, then any cascade.
- Primary button is
Verb + Nounand matches the title verb. NeverConfirm,OK, or a bare verb on a destructive primary. - The cancel literal stays
Cancel. Acknowledgment-only modals useDone, neverOKorClose. - Close irreversible bodies with
This cannot be undone.; close cascade-only bodies withSome effects cannot be undone.. - Pair the success toast verb one-to-one with the primary button:
Delete Projectbutton,Project deletedtoast.
Accessibility
- Set
aria-labelledbyto theModal.Titleid so screen readers announce the title on open. - Keep the cancel button literally
Cancelso screen-reader users hear a stable dismissal label across destructive flows. - After an error inside the
Modal, keep focus inside so the user can retry; after success, return focus to the trigger.