Flip the popover when it would hit the viewport edge
Aliases: flip placement · collision flip · viewport avoidance
What it is
A popover opens in a preferred direction against its trigger — often below. Near the edge of the viewport or a scroll container, that direction clips the layer out of the window. Collision flipping chooses, before paint, another direction that still fits the whole layer: below becomes above, right becomes left, with a shift if needed. It keeps the layer fully visible. It does not change who the anchor is, and it does not decide whether the layer covers the trigger.
Why it happens
The viewport is a hard clip. The part of the layer that falls outside is, for the user, nonexistent, and a menu looks as if it only had those few items. Preferred direction is a prior (most desktop menus open down); when the edge arrives, visibility outranks the prior. The flip should finish in the opening frame, not clip first and then flip, or a truncated menu will flash. Both the viewport edge and the nearest scrollport edge count: a button against the bottom of the page should flip inward, not toward already-invisible window chrome. When no direction fits, flipping is not enough and the layer must translate along the anchor axis or scroll inside; translation should keep contact with the trigger’s edge, or the flip succeeds and ownership is lost. Direction is a geometry decision and should not jump with content length on every open, or the same button’s menu is sometimes above and sometimes below and spatial memory cannot form.
Studying it
Place the trigger on the four edges and four corners of the viewport. Record opening direction, whether any of the layer is clipped, and whether people find items that would have been clipped. Independent variables: preferred direction, viewport size, layer height. Dependent variables: clipped pixels, whether the first open is fully visible, whether direction is stable across repeated opens of the same trigger. Corners hit two edges at once and should be scored separately.
Where it stops holding
On a tiny viewport every direction clips; flipping cannot save it, and a full-width bottom sheet should take over. When a fixed direction is part of the control’s metaphor (a select that always expands down), a flip breaks the metaphor; prefer internal scroll, still flush to the trigger, over becoming a different control above. If motion plays the preferred direction and then flips, the layer looks as if it jumped; it should appear in the final direction.
Applying it
- Before opening, run collision against the viewport and the nearest scrollport, and pick a direction that fits the whole layer. Prefer a stable direction for the same trigger in one session.
- If it still does not fit, translate along the anchor edge or scroll inside the layer; do not leave items outside the window.
- Do not paint a clipped state and then correct it.
- How to check: drag the trigger to each corner and open. The layer should be fully visible. Any missing slice means that collision is not covered.