← back

The popup contract

Last updated 2026-07-13 09:44 WEDT ยท now:

Cody3's mutation found six controls buried in scrolling popups. Five were reading screens and his fix was right. One was this โ€” and it is the reason the law exists.

๐Ÿ”ด What ships today โ€” the person-popup

Three choices about another person. The card scrolls (maxHeight:88vh ยท overflowY:auto). The close button is pinned, so the card looks finished. Scroll it.

Ana
How do you want to hold this person at events? This choice is private โ€” they are never told, and it quietly shapes what we suggest and who we seat you near.
the fold โ†‘
The โœ• was never the control at risk. The lanes are the controls โ€” and Avoid is last. If the card overflows, the option below the fold is the strongest protection a person can ask for. They see discomfort and give space, and pick the weaker one because it was the last one they could see.

โœ… What the law actually asks for โ€” it fits

Same three choices. No scroll. Symbols carry the options; the words about a control appear after it's tapped. This is Davi's own remedy: put less on that level.

Ana
How do you want to hold Ana? Private โ€” she is never told.
Tap one to see what it does.
All three options are visible at once. Three buttons always fit โ€” this needed no nesting at all, just the overflow removed and the prose moved behind a tap. A popup is a choice; every option must be visible, or the choice you are offering is a lie.
โญ And pinning made it HARDER to see. A card with a pinned โœ• and visible content reads as finished โ€” the pinned chrome disguises the scroll. Before the fix, an alert reader might notice the card was cut off. After it, the card looks complete and the third option is still gone. Applying the screen remedy to a popup is worse than doing nothing.

The contract โ€” two shapes, two remedies, never interchangeable

shapewhat it isremedy
POPUP A transient layer offering a bounded set of choices about the thing you just tapped. MUST NOT SCROLL. Ever. Show less at this level (symbols, no prose on the buttons); nest the detail one level deeper. overflow is never the answer.
LIGHTBOX SCREEN Replaces the surface. Content โ€” prose, a diagram โ€” not controls. Has its own close. Content may scroll. The close and every control must be pinned outside the scroll flow. An essay that scrolls is a book; an essay whose close scrolls away is a trap.
PANEL / PALETTE Persistent tray or list. Not transient, not tapped open. Homogeneous peers. The list may scroll. A unique control โ€” Apply, Export all, Done โ€” may never live inside it.

One testable rule for all three: a control inside a scrolling region must be PINNED, or be one of a list of peers. And a popup has no scrolling region at all.

๐Ÿ”ด The primitive licenses the bug

DraggablePopup.jsx, in its own contract, says: "size to fit the viewport; inner content scrolls when it overflows."

The popup primitive documents the exact behaviour the law forbids. Every popup built on it inherits permission to scroll โ€” so this bug is not a mistake anyone made, it is a bug the primitive mints. A law repealed in a comment. Proposed replacement:

A popup FITS. If content overflows: show less at this level, and nest the detail one level deeper. overflow is never the answer. If a surface genuinely must scroll, it is not a popup โ€” it is a lightbox screen, and it must pin its close and its controls.