Choosing an overlay
Six things in this set float above the page, and they look similar enough that picking the wrong one is easy. The difference is never how they are drawn — it is what they promise the reader.
Which one
Section titled “Which one”| Interrupts? | Holds actions? | Opens on | |
|---|---|---|---|
| Dialog | yes | yes | a deliberate click |
| ConfirmDialog | yes, harder | yes, one of them destructive | a deliberate click |
| Drawer | yes | yes | a deliberate click |
| Popover | no | yes | a deliberate click |
| PreviewCard | no | no | hover, after a pause |
| Tooltip | no | never | hover or focus |
Dialog stops the work. Everything behind it goes inert — not merely dimmed, but out of reach of the keyboard and of a screen reader — so use it when the answer is genuinely needed before anything else can happen.
ConfirmDialog is a Dialog for a choice that cannot be taken back. It
announces itself as alertdialog, and clicking away does not dismiss it —
an answer given by a stray click is exactly what it exists to prevent. Escape
still closes it, deliberately: a popup with no keyboard exit is a trap, and
pressing Escape is a decision rather than an accident. Reach for it when the
action deletes, overwrites or sends.
Drawer is a Dialog that arrives from an edge. Same interruption, more room; it suits a panel of settings or a form that would look cramped in a box.
Popover floats next to what opened it and leaves the page alone. It can hold controls — a filter, a small form, a menu of options. If the reader can carry on without answering it, this is the one.
PreviewCard is what a link looks like before you follow it. It appears on hover after a pause, and it is not for anything the reader has to click: appearing on hover means it can vanish on the way to the thing inside it.
Tooltip names a control that is otherwise only an icon. It carries no interactive content at all — never a link, never a button — because there is no way to reach one with a keyboard. If you want to put a button inside a tooltip, you want a Popover.
What they all get right
Section titled “What they all get right”The behaviour is Base UI’s, which means it is the same behaviour in each of them and it is the part that is hard to write:
- focus moves into the overlay when it opens and returns to whatever opened it when it closes;
Escapecloses what should be closeable;- a modal locks the scroll and marks the page behind it inert;
- the popup is named by its own title through
aria-labelledby, without anyone wiring up an id.
What is dowel’s is the clothes — and the enter and the leave, which are class
lists rather than a state machine, because Base UI puts data-open,
data-closed and data-starting-style on the element for you.
And one rule about size, which holds for every one of them and for menus, lists and toasts too: anything drawn over the page fits the window on both axes, and scrolls inside itself when there is more than fits. A popup placed against a trigger is held to the room its positioner says is left between the trigger and the window’s edges; a dialog, a drawer or a toast, to the window. The scroll is contained, so reaching the end of a long menu does not start scrolling the page underneath it.
A dialog, a drawer, a confirmation, the palette and a toast are columns, and
only one part of each gives way — the body, the list, the description — so the
title and the answer stay in reach while a long form moves between them. Put a
long form in DialogBody, not straight into the popup.
The short example on the stand always fits, so the rule is not checked by looking at one: a gate hands every surface in every variant far more content than any window holds.
Stacking
Section titled “Stacking”Overlays sit on named layers rather than on numbers picked in the moment:
--z-popup: 10; /* a popup in the flow */--z-sticky: 20;--z-menu: 30;--z-floating: 40; /* Popover, PreviewCard */--z-overlay: 50; /* the scrim */--z-modal: 60; /* Dialog, ConfirmDialog, Drawer */--z-palette: 70;--z-toast: 80; /* has to clear everything */A component reads these directly — [z-index:var(--z-modal)] — because
Tailwind has no z-index namespace and z-50 would be a literal fifty with
nothing to say about what it covers.
A popup inside an overlay
Section titled “A popup inside an overlay”The ladder answers “who covers whom” for things on the page, and has nothing to say about a popup opened inside an overlay: a select in a dialog is a 30 beside a 60, a menu in a drawer the same, a select in a popover a 30 beside a 40. Each opens underneath the thing that asked for it.
So every overlay opens a layer for its content — a
host inside its own portal where the popup rungs are raised one above the
overlay, worked out by the stylesheet from the ladder — and every popup
portals into the layer it was opened in. A select in a popover in a dialog
climbs to 62 without anyone writing a number. Nothing to do at the call site;
a product’s own full-screen stage takes LayerProvider above="overlay".