Overlays
Eleven components put content above the page. The choice between them is a choice about focus — who has it, where it returns, and what Escape closes.
What it solves
Putting something above the page is easy. What is hard, and what every overlay bug is about, is the three questions that follow: does the background still work, where does the keyboard go, and what happens when the person presses Escape.
The library answers all three in one place — a shared layer stack — so the answers are the same for every overlay on the page. That matters most when there are two.
Anatomy
Choose by what the content is, not by how it should look. The library states the condition for each:
- Your own layout above the page —
GrModal. The base every modal thing is built on; take it when the ready-made shapes do not fit. - A window with a header, a body and a footer —
GrDialog. The shape you need nine times out of ten. - The action is irreversible —
GrConfirmDialog. A separate component, not a dialog with a red button: the question and the danger are its subject. - One value is needed —
GrPromptDialog. A whole form for a single field is a form you now have to lay out. - A panel arrives from the edge —
GrDrawer. Modal or not; see below, because that flag changes the keyboard. - Your own content at an anchor —
GrPopover. Tied to the trigger, not to the centre of the screen. - A menu of its own items —
GrDropdown. A list of actions next to what they act on. - Actions over a row or a tree node —
GrContextMenu. Brings them to the pointer instead of making the person travel to a toolbar.
The two axes underneath: modal or not (does the background keep working) and anchored or centred (is it about one element or about the page).
Example
Do and don’t
Do — Let the stack return focus
Closing returns focus to the trigger, and the layer stack does that itself. Moving
focus by hand through nextTick or a timeout competes with it — and loses on the
second overlay, where the winner depends on timing.
Don’t — Open an overlay from an overlay for no reason
Two layers deep, «back» stops meaning anything: Escape closes the top one, and the person expected the whole thing to go. If the second layer is a confirmation, that is the case it was built for; anything else is a wizard wearing a stack.
Do — Non-modal drawer when the page is still the point
:modal="false" removes the focus trap: Tab goes back to the page, which is what
a filter panel or an inspector is for. The overlay is help, not a wall.
Don’t — Trap focus in something that is not a decision
A modal drawer over a table means the table cannot be reached with the keyboard until the drawer closes. If the person is meant to look at both, the trap is the bug — not the layout.
Do — Ask the dangerous question in its own component
GrConfirmDialog exists because «delete» and «save» must not look like the same
dialog with a different colour. The component carries the question, the wording
of consequences and the emphasis on the safe answer.
Don’t — Confirm everything
A confirmation on a reversible action teaches people to dismiss confirmations, and then the one that mattered is dismissed too. Undo beats confirm wherever undo is possible.
Accessibility
Overlays are the place where keyboard support is most often half-finished, and a half-finished pattern is worse than none: a screen reader announces a role the behaviour does not match.
Escape closes the top layer, not all of them. With two overlays open, one press should not clear the screen — the person is undoing one step.
The focus trap is a property of modality. GrModal and everything built on
it — GrDialog, GrConfirmDialog, GrPromptDialog — cycle Tab inside. A drawer
with :modal="false" deliberately does not, and that is the whole point of the
flag.
Return is not optional. The keyboard cannot be left at the top of the document after closing; the person was somewhere, and that somewhere is where the work continues.
The contracts below come from the library and are tested there. What no component can decide for you is how many layers a screen deserves — and the honest answer is usually one.
Components in this pattern
The list is built from frontmatter, not from links in the prose: renaming a slug does not lose it.
GrModaloverlaysGrDialogoverlaysGrConfirmDialogoverlaysGrPromptDialogoverlaysGrDraweroverlaysGrPopoveroverlaysGrDropdownoverlaysGrContextMenuoverlays
Keyboard
Contracts come from the library. The pattern does not restate them — it points at them.
GrModalComponent contractGrDialogComponent contractGrConfirmDialogComponent contractGrPromptDialogComponent contractGrDrawerComponent contractGrDropdownComponent contractGrContextMenuComponent contract