Modal
Blocking. Elevation 3. role="dialog" aria-modal="true".
Spec
- Labelled by the title (
aria-labelledby). - Focus trap while open. Restore to the trigger on close.
- Close: Escape, close button, cancel (secondary).
- Widths: sm 400, md 560, lg 720. Max height 90vh.
- Compact: sheet from the block-end, not a floating card.
- Footer: secondary + one primary. No second filled action.
- Do not stack modals.
- Not for non-blocking status — that is Toast or Alert.
Live demo
Runnable controls. Not a screenshot. Paper / Ink in the header recolors tokens.
Focus trap, Esc, one primary. Compact becomes a block-end sheet.
Delete this panel?
Metrics on this canvas will not include it. The series stay in the feed.
Mute ingest delay
Stops toasts for this metric until 18:00.
Do / Don't
| Do | Don't |
|---|---|
| Trap focus. Restore it. | Open a second modal on top. |
| One primary in the footer. | OK as the primary. Name the verb. |
| Sheet on compact. | A 720px dialog on a phone canvas. |
Motion
| Property | Duration | Easing | Trigger | Reduced motion |
|---|---|---|---|---|
opacity + scale(0.98→1) | 280 / 160 | --ease-out | open / close | opacity only |
translateY | 280 / 160 | --ease-out | open / close | opacity only |
Accessibility
- Initial focus: the first field, or the primary if there is no field. Not the overlay.
- Focus cycle stays inside. Shift+Tab from the first control goes to the last.
- Title is the accessible name. Don't rely on placeholder text.
- Hit 44px on close, cancel, primary.
- These notes describe construction. They are not a guarantee of WCAG conformance. Validate with axe, keyboard, and operators. See Accessibility.