Modal
A dialog overlay that focuses user attention on a task or decision. Use when an action requires explicit user confirmation. Don't use for non-critical information that can be shown inline — use Alert instead.
Description
What it does
Modal interrupts the user's current flow to present a task, decision, or critical information that must be addressed before continuing.
Where it appears
Confirmation dialogs ("Delete this project?"), short data-entry forms, destructive action warnings, and content previews that don't warrant a full page.
Why it exists
Some actions require deliberate confirmation rather than immediate execution. Modal creates a bounded context where the user's full attention is on a single decision, then returns them to where they were.
Dependencies
Not for routine feedback — if no decision is required, use Alert instead. If the message is a system-level notification, use Notification Modal.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Backdrop | Required | Semi-transparent overlay behind the modal. Clicking it dismisses the modal unless the action is destructive or data entry is in progress. |
| Header | Required | Contains the modal title, and a status icon to its left in the status variants. Must be linked to the dialog via aria-labelledby. |
| Header actions | Optional | Extra icon buttons in the header, beside the close button (for example an open-in-new-window link). |
| Body content | Required | The main content. Keep it focused — modals are not a canvas for complex layouts. |
| Close button | Required | × button at the right of the header. Always present unless the action is a required confirmation with no dismissal path. |
| Secondary action | Conditional | Cancel, Go back, or an alternative action. Omit when the close button already serves this role. |
| Primary action | Required | The main call to action. Use a destructive button style for irreversible actions. |
Variants
This will make the consultation visible to the public and open it for submissions.
Confirmation
Asks the user to explicitly confirm a reversible action before it executes
Asking the user to confirm an action before it executes. "Publish this consultation?" Always provide a clear Cancel path.
This will permanently delete all responses, files, and settings for Riverfront Consultation. This cannot be undone.
Destructive confirmation
Confirms an irreversible, high-consequence action using a danger-styled primary button
The action cannot be undone. Delete, remove, archive. In Figma this is the Danger variant: a danger status icon beside the title and a danger confirm button. State explicitly what will be deleted.
Form
Contains a short data-entry form scoped to the triggering context
Short forms that logically belong in context with the triggering page. Keep them brief — if the form grows complex, use a full page instead.
Summary of the terms a user must review before proceeding.
Informational
Presents read-only content that needs the user's focused attention
Displaying content that needs focused reading — terms, previews, help content. Use sparingly; consider whether a page or drawer would serve better.
Usage guidelines
When to use
- Confirming an irreversible or high-consequence action.
- Collecting a small, self-contained piece of input that doesn't warrant navigating away.
- Displaying content that requires focused attention and explicit dismissal.
When not to use
- For feedback after an action — use Alert.
- For complex forms or multi-step flows — use a page or wizard pattern.
- As an entry point for navigation — don't open modals from within modals.
- For low-stakes confirmations — avoid over-confirming routine actions. Reserve modals for genuinely important decisions.
Do / Don't
Do
Write modal titles as plain questions or statements: "Delete this project?" or "Export stakeholder data". Not "Confirmation Required".
Don't
Don't nest modals. If a modal action opens another modal, the flow needs redesigning.
Do
For destructive actions, make the consequence explicit: "This will permanently delete 47 responses and cannot be undone."
Don't
Don't make "Cancel" the primary button. The primary action should always be the most likely next step.
Layout & Spacing
Modals are centred horizontally and vertically in the viewport. They have a maximum width and scroll internally when content overflows — the backdrop and modal chrome stay fixed.
| Element | Spec |
|---|---|
| Width | 480 / 640 / 800px (S / M / L), or fullscreen; 90vw on small screens. --orbit-modal-size-*-width |
| Max height | 85vh — body scrolls internally beyond this |
| Header padding | 12px top, 24px left, 12px right (beside the close button); 8px between a status icon and the title. --orbit-modal-header-* |
| Body padding | 24px on all sides. --orbit-modal-body-padding |
| Footer padding | 24px left, right and bottom; 8px between buttons. --orbit-modal-footer-padding, -actions-gap |
| Border radius | 12px (none when fullscreen). --orbit-modal-radius |
| Shadow | Large elevation shadow. --orbit-modal-shadow-* |
| Backdrop colour | --orbit-modal-scrim |
| Title | 20px heading font (Lora), medium weight |
| Body text | 16px, regular weight |
Component tokens
Modal and Notification Modal share one set of framework-neutral CSS variables. Notification Modal is the status variants (danger, warning, success, info), which add a status icon colour; the confirm button comes from Button's tokens.
| Token | What it sets |
|---|---|
--orbit-modal-background, -radius, -scrim |
Surface, corner radius (overlay radius) and the backdrop colour. |
| `--orbit-modal-shadow-{offset-x | offset-y |
| `--orbit-modal-size-{s | m |
| `--orbit-modal-header-{padding-block | padding-inline-start |
| `--orbit-modal-title-{color | font-size |
| `--orbit-modal-body-{padding | gap |
| `--orbit-modal-footer-{padding | gap |
| `--orbit-modal-{danger | warning |
| Element | Token |
|---|---|
| Background | --orbit-modal-background |
| Backdrop | --orbit-modal-scrim |
| Title text | --orbit-modal-title-color, --orbit-modal-title-font-size, --orbit-modal-title-font-weight |
| Body text | --orbit-modal-body-color, --orbit-modal-body-font-size |
Engineering notes
- The native
<dialog>element traps focus automatically when opened withshowModal(). Custom implementations must implement a focus trap manually — focus should cycle through interactive elements within the modal and not reach page content behind it. - Always return focus to the element that triggered the modal on close. Without this, keyboard users lose their position in the page.
- Don't use
display: noneto hide modals — use thehiddenattribute or thedialogelement's open state so screen readers don't read hidden content. - Avoid opening modals on page load. They interrupt users before they have context and are a common cause of accessibility failures in form-heavy applications.
Keyboard interaction
| Key | Action |
|---|---|
| Tab | Moves focus forward through interactive elements within the modal. Focus is trapped — it does not leave the modal. |
| Shift + Tab | Moves focus backward through interactive elements within the modal. |
| Escape | Closes the modal and returns focus to the triggering element. Always implement this unless the modal requires a mandatory decision. |
| Enter or Space | Activates the focused button. |
Why it matters
Focus management is the most commonly failed accessibility requirement in modals. When a modal opens, focus must move into it — otherwise keyboard and screen reader users are stranded on the page behind it. When it closes, focus must return to the trigger — otherwise users lose their place. Both are required for a modal to be genuinely accessible.
ARIA
| Role or attribute | When to use | Example |
|---|---|---|
role="dialog" | Applied to the modal container. Identifies the element as a dialog. The native <dialog> element provides this implicitly. | <div role="dialog" aria-modal="true" aria-labelledby="modal-title"> |
aria-modal="true" | Applied to the modal container. Tells screen readers that content outside the modal is inert. Required on custom implementations. | <div role="dialog" aria-modal="true"> |
aria-labelledby | Applied to the modal container. Points to the modal's title element by ID. Ensures the modal title is announced when it receives focus. | <div role="dialog" aria-labelledby="modal-title"><h2 id="modal-title">Delete project</h2> |
aria-describedby | Applied to the modal container. Optional. Points to the body text when a brief description should be announced alongside the title. | <div role="dialog" aria-describedby="modal-desc"><p id="modal-desc">This action cannot be undone.</p> |
How to apply it
When a modal opens, move focus to the modal container or to the first interactive element inside it — whichever gives the most useful context. For confirmation modals, focusing the container first means the title and description are announced before anything is activated. For form modals, focusing the first input is often more efficient.
Things to avoid
- Don't allow focus to leave the modal while it's open. Page content must not be reachable via Tab.
- Don't remove the modal from the DOM while it's open with animation — this can confuse screen readers. Animate out, then remove.
- Don't use
role="alertdialog"unless the modal is communicating a critical error that demands immediate attention. For confirmations and forms,role="dialog"is correct. - Don't auto-close modals on a timer. Users may need more time to read or act.