Surfaces & Overlays (Desktop)
Cards and panels
- A card exists to group related content and separate it from its surroundings — if a screen is entirely cards with nothing between them, the card boundary is doing no work (this is the "card soup" anti-slop tell from foundations). Use flat sections for most content; reserve actual card treatment for content that's genuinely a discrete, movable, or comparable unit (a project card in a grid, a notification, a file preview).
- Padding inside a card should come from the spacing scale (usually 16 or 24px), consistent across every card of the same type in the app.
- Cards get
surface-raised+ theraisedelevation level (see color-system) — not the same background as the page behind them.
Modals / dialogs
- Use for: decisions that block progress until resolved (confirmations, required forms, destructive-action confirmations). If the user can safely ignore it and keep working, it shouldn't be a modal.
- Sizing: cap width (typically 400–560px for simple dialogs, wider only for genuinely content-heavy ones like a settings modal) — a modal that stretches to fill a maximized window looks like a mistake, not a design choice.
- transform-origin stays centered — unlike popovers, modals aren't anchored to a trigger element, so they should scale/fade from the center of the viewport, not from wherever the button that opened them happened to be.
- Focus trapping: focus must move into the modal on open and can't leave it via Tab until it closes; Escape closes it (unless it's blocking an unsavable, irreversible action, in which case make that explicit rather than silently ignoring Escape).
- Backdrop: a dimmed, semi-opaque backdrop (not a full blur — expensive and usually unnecessary) that closes the modal on click, except for destructive confirmations where an accidental backdrop click shouldn't discard an in-progress irreversible action.
- Destructive confirmations need the specific consequence stated in the body text (not just "Are you sure?") and the destructive button should be the non-default, clearly danger-colored one — never make "delete" the button that gets focus by default.
Popovers and dropdown menus
- Origin-aware: a popover should visually emerge from the control that triggered it (
transform-originset to the trigger's position), not scale in from the center of the screen — this is one of the more noticeable "someone actually cared" details, cheap to implement, easy to skip. Seedesktop-ui-motion. - Dismiss on: click outside, Escape, or selecting an item (for menus). Clicking the trigger again should toggle closed, not open a second instance.
- Sizing: width should fit its content up to a max width, not stretch to match the trigger's width by default unless the content specifically benefits from that (e.g. a select-style dropdown).
- Context menus (right-click) follow the same origin-aware and dismiss rules, positioned at the cursor, and should respect the window edge — flip direction rather than rendering off-screen.
Tooltips
- Delay before first appearance (~400–700ms) to avoid firing on every incidental hover, but once one tooltip in a group (e.g. a toolbar) is showing, subsequent tooltips in that same group should appear instantly with no delay — this single behavior makes a whole toolbar feel faster without giving up the anti-accidental-trigger delay on first hover.
- Content: short, functional (what the control does, or its keyboard shortcut) — not marketing copy, not a full sentence when three words will do.
- Never put essential information only in a tooltip — if a user needs to know something to safely use the control, it needs a more persistent home (a label, inline help text) since tooltips are easy to miss and don't exist on touch.
Accessibility
Modals and dialogs must trap focus inside themselves while open, expose a dialog role to the platform accessibility API, and return focus to whatever opened them when they close — the classic failure is a modal that a keyboard user can Tab straight out of into the page behind it. Popovers and menus close on Escape and on an outside click, and reopen with focus landing on the first meaningful item, not left behind on the trigger. See desktop-ui-accessibility-i18n.
Review format
| Before | After | Why |
|---|---|---|
| Popover scales in from screen center | transform-origin set to the trigger element |
Popovers are anchored to a specific control; scaling from center looks disconnected from what opened it |
| Modal stretches full-width on a maximized window | Capped max-width (e.g. 480px) regardless of window size | An unbounded modal reads as unstyled, not intentional |
| "Are you sure?" as the entire confirmation body | "This will permanently delete 12 files. This can't be undone." with a danger-colored confirm button | Vague confirmations don't actually inform the decision; specific consequences do |