# Overlays

> Surfaces that appear above the interface for a moment: where they sit, how they close, where focus goes.

An overlay is a surface that appears above the interface for a moment — a menu,
a popover, a list of suggestions — attached to the control that opened it, or to
the point it is about. It keeps people in context: the interface they came from
stays in view, and closing the overlay returns them to it.

## Best practices

**Attach the overlay to its control.** Place it against the control that opened
it, on the side with room, so the relationship is evident. When there is no room
on the preferred side, move it to the other rather than letting it be cut off.

**Or to the point it is about.** An overlay with no control of its own — a
context menu at the pointer, a toolbar over a selection — is placed against that
point or rectangle of the view, in the same way: beginning there, extending
toward the end of the line in the direction its own text runs, and moved to the
other side at an edge of the view. Where it fits on neither side, it is held
within the view. It is where it says wherever in the page it happens to be
written: inside a panel that has been moved, it is still at the point.

**Keep it above everything.** An overlay should never be clipped by a scrolling
region or hidden beneath other content.

**Let people dismiss it without deciding.** Escape and a press outside close an
overlay and change nothing. Pressing its control again closes it too, and so
does focus moving somewhere outside it.

**Give Escape to what is being done first.** With focus inside an overlay,
whatever has focus hears Escape before the overlay does: a field abandons what
was typed, and only the next Escape closes the overlay. While an input method is
composing, Escape is its own.

**Decide whether a press outside is also a press.** A menu, like the platform's
own, takes the press that dismisses it: what is under the pointer is not
pressed too, except another control that opens a menu, so that moving from menu
to menu takes one press. An overlay that sits beside the work it serves — a
popover of settings — lets the press through, so that closing it and going on
are one gesture. A sheet over a dimmed interface always takes the press.

**Block the page for what must be answered.** A dialog is modal on every
screen, not only on a phone: while it is open the rest of the page is inert — to
a pointer, the keyboard and assistive technology — and does not scroll, and a
scrollbar that took room keeps it, so that the page does not shift. A press
outside it reaches nothing beneath. An alert that must be answered is not closed
by such a press at all, and focus stays where it was, though whatever was opened
from the alert closes; Escape still closes it.

**Close one level at a time.** When one overlay opens another — a submenu, a
popover from within a popover — Escape closes only the topmost, and a press in
an outer overlay closes only those above it. Closing an outer overlay — by any
means — closes everything opened from it. The order is the order in which they
are nested, also when both are open from the start.

**Move focus in, and bring it back.** When an overlay opens, focus moves into
it: to the first control, or to the overlay itself when there is nothing to
operate. When it closes, focus returns to the control that opened it — unless
the person has already moved focus elsewhere, as by pressing another control.
With no control to return to, or one that has since become unavailable, focus
returns to whatever had it before the overlay opened. Focus is returned even if
the overlay's content is removed from the page in the act of closing.

**Do not outlive the control.** An overlay whose control becomes unavailable, or
is removed, closes.

**Say what the control opens.** A control that opens an overlay states that it
does, what kind of overlay it opens, and whether it is open.

**Fit the screen.** An overlay is never taller than the view: what does not fit
scrolls within it, and the page behind does not scroll with it.

**Take no presses while leaving.** An overlay that is fading away is already
gone as far as the pointer is concerned, so a second press cannot act on it.

**Use an overlay for what is brief.** Choices and small tasks belong in an
overlay; anything people need to keep in view, or return to, belongs in the
interface itself.

## Platform considerations

**Pointer and keyboard.** An overlay sits beside its control and is dismissed by
Escape or a click outside.

**Touch, on a phone.** Space is short and a finger covers what it presses. An
overlay rises from the bottom edge as a sheet, across the full width, above a
dimmed interface; a tap outside it closes it.

A sheet shows a grabber at its top, which says it can be dragged away. It
follows a finger that drags it down. Let go past a third of its height, or
flicked, it closes; otherwise it returns. For people who have asked for less
motion it returns at once rather than gliding, though it still follows the
finger, which is the finger's motion and not its own.

A sheet is modal. While it is open the rest of the page is inert — to a finger,
to the keyboard and to assistive technology alike — and does not scroll behind
it; a sheet that is a dialog says that it is modal. All of it is put back
exactly as it was found when the sheet closes, whatever the order in which
nested sheets close, and also if the sheet is removed from the page while open.

The platform's way back — the back gesture on Android — closes the topmost
sheet, where the browser reports it.

An overlay opened from within a sheet rises as a second sheet over the first,
unless it is a further level of the same thing — a submenu of a menu. Such a
level takes the place of the sheet it was opened from: it covers it, under the
same scrim, and a swipe down closes both. What opens such a level gives it a way
back.

**Several documents, several roots.** An overlay belongs to the document it is
in: it answers that document's keys and presses, which matters for an interface
drawn into a frame or another window. Overlays of separate applications on one
page do not disturb one another's placement.

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### Opening

- The control that opens it states whether it is open, and what it opens.
- It appears above everything else on the page.
- It is placed against the control that opened it.
- With no room on its side, it flips to the other.

### Focus

- Opening moves focus to the first thing inside that takes it.
- With nothing inside to take it, focus moves to the overlay.
- Closing returns focus to the control that opened it.
- Asked to open when it is already open, it still moves focus as asked.
- Closing by pressing another control leaves focus on that control. *(Chromium, Firefox, WebKit)*

### Dismissal

- Escape closes it.
- Escape pressed to an input method that is composing is left to it.
- What has focus inside hears Escape first, and one that claims it keeps the overlay open.
- Focus that moves outside closes it. *(Chromium, Firefox, WebKit)*
- A press outside closes it.
- A press inside keeps it open.
- Pressing the control that opened it closes it, rather than closing and reopening.

### Modal overlays

- A press outside a modal overlay only closes it: what it lands on is not pressed.
- The press after that one is an ordinary press.
- A press on a control that opens another overlay opens it at once. *(Chromium, Firefox, WebKit)*
- On a phone, where an overlay is a sheet, a press outside only closes it. *(Chromium (touch), WebKit (touch))*
- A press outside an overlay that is not modal also presses what it lands on. *(Chromium, Firefox, WebKit)*

### Stacking

- An overlay opened from within another stays open with it.
- Escape closes only the topmost, and focus returns to the control that opened it.
- A press in the outer overlay closes only the inner.
- Closing the outer closes the inner with it.
- Closing the outer by any means closes the inner with it.
- An overlay keeps its place however often its owner renders.
- Overlays that begin open, one inside another, stack as they are nested.

### Anchoring at a point

- Opened at a point, it begins at the point, wherever it is rendered. *(Chromium, Firefox, WebKit)*
- Opened against a rectangle, it sits beneath it, from its start edge. *(Chromium, Firefox, WebKit)*
- With no room below the point, it opens above it. *(Chromium, Firefox, WebKit)*
- With no room above the point, one that opens above opens below. *(Chromium, Firefox, WebKit)*
- With no room toward the end of the line, it opens toward the start. *(Chromium, Firefox, WebKit)*
- In right-to-left text it opens leftward from the point, and with no room there rightward. *(Chromium, Firefox, WebKit)*
- Where it fits neither above nor below the point, it is kept within the view. *(Chromium, Firefox, WebKit)*
- Opened at another point while it is open, it moves there. *(Chromium, Firefox, WebKit)*
- With no control to return to, closing returns focus to what had it before.

### What changes beneath it

- Content that arrives after the overlay was opened is shown.
- Focus returns to the control when the content is removed in the act of closing.
- A control that can no longer be used closes its overlay, and focus goes back to where it was before.
- A control that is removed closes its overlay, and focus goes back to where it was before.
- An overlay in another document answers the keys and presses of that document.
- Overlays of separate React roots on one page each sit against their own control.

### Blocking overlays

- One that blocks makes the page behind it inert and still on every screen, and says it is modal.
- One that blocks, taken off the page while open, leaves nothing inert behind it.
- A press outside one that is not dismissed by it leaves it open with focus inside, but closes what was opened from it.
- Opened without being told where, focus goes where its owner said it should.

### Sheets

- A sheet shows a grabber at its top, which says it can be dragged away. *(Chromium (touch), WebKit (touch))*
- A sheet follows the finger that drags it down, and let go a little way down it returns. *(Chromium (touch), WebKit (touch))*
- Dragged down past a third of its height and let go, a sheet closes. *(Chromium (touch), WebKit (touch))*
- Flicked down, a sheet closes though it was not dragged far. *(Chromium (touch), WebKit (touch))*
- Asked for less motion, a sheet let go returns at once rather than gliding. *(Chromium (touch), WebKit (touch))*
- While a sheet is open the rest of the page is inert, and as it was found once the sheet has closed. *(Chromium (touch), WebKit (touch))*
- A sheet opened from a sheet leaves the page inert until both have closed. *(Chromium (touch), WebKit (touch))*
- A swipe down on a sheet opened from a sheet closes that one alone. *(Chromium (touch), WebKit (touch))*
- A sheet taken off the page while open leaves nothing inert behind it. *(Chromium (touch), WebKit (touch))*
- A sheet that is a dialog says that it is modal, for as long as it is open. *(Chromium (touch), WebKit (touch))*
- The page behind a sheet does not scroll. *(Chromium (touch), WebKit (touch))*
- The platform's way back, where the browser tells of it, closes only the topmost sheet. *(Chromium (touch), WebKit (touch))*
- One that takes the place of the sheet it was opened from covers it, under the one scrim, and a swipe down closes both. *(Chromium (touch), WebKit (touch))*

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/overlay.json`
