Bottom sheet
The mobile-first dialog: anchored to the bottom of the viewport on phone, centred as a modal on desktop. Header, scrollable body, sticky footer. Replaces the bespoke .sheet / .more-sheet / .modal mobile variants shipped by Admin, Parent, Student, Gold, and Owner.
Shell at every breakpoint
Bottom-anchored on phone, centred on desktop. Greyscale wireframes — structure only.
Live examples
Where to see this shell in action — reference docs, cookbook recipes, and live demos.
Detail sheet
The default: tap a row card and it opens. Headline, body content, and a sticky footer with the primary action. Header carries a close button and a drag handle for vertical-swipe dismiss.
Action sheet
A list of destructive / lateral actions surfaced from a "…" button. Each row is a tap target with an icon tile on the left.
Desktop dialog
≥ 720 px viewport, the sheet centres as a 520 px-wide dialog with rounded top & bottom corners. Same parts — only the entrance is different (fade + lift, not slide-up).
Parts
| Property | Value | Notes |
|---|---|---|
| scrim | ink @ 55% opacity | 200 ms fade in / out |
| radius (phone) | 18 px top, 0 bottom | Anchored to viewport edge |
| radius (desktop) | 14 px all corners | Free-floating dialog ≥ 720 px |
| max height | 90 vh phone, 80 vh desktop | Body scrolls when over |
| grab handle | 38 × 4 px, --border-strong | Phone only; hidden on desktop |
| header | flex, padding 10–18, border-bottom subtle | Sticky — header stays visible while body scrolls |
| footer | safe-area padding, border-top subtle | Buttons stretch to fill; primary on the right |
| entrance (phone) | translateY 100% → 0 | 260 ms cubic-bezier(0.2,0,0.1,1) |
| entrance (desktop) | translateY 20 → 0, opacity 0 → 1 | 200 ms ease-out |
Shared rules
Close on scrim tap, Escape key, drag-down past a threshold, and explicit close button. Each is the only one some users know.
Stack sheets. If a sheet opens another, you've designed a wizard — use a stepper instead.
Use a sheet for any modal that's > 1 viewport tall on phone. The internal scroll inside the sheet is gentler than full-page scroll under chrome.
Put navigation links in a sheet. Sheets are for the current record / current action — not a substitute for the sidebar.
Trap focus inside the sheet when open. Tab cycles through interactive children only; Shift+Tab from the first wraps to the last.
Animate close as a slow slide. 200 ms or less — operators want the canvas back fast.
Accessibility
- The sheet is a
<div role="dialog" aria-modal="true" aria-labelledby="bs-title">. The header H3 carries that ID. - Open: move focus to the close button (or the first interactive child). Close: restore focus to the element that opened the sheet.
- Inert the rest of the page (
inertattribute on the app container) so AT can't reach the background. - Drag handle is a visual cue, not interactive — keyboard users use Escape or the close button.
Related
- Modal & sheet — the broader modal family (alert dialog, confirm, etc.).
- Row card — the primary opener for detail sheets.
- Bottom tabs — the "More" tab opens a sheet of overflow destinations.
- Detail view — when the detail is too big for a sheet, use a full screen.