Skip to content

Anchored overlays

An anchored overlay is any surface whose position is derived from something else on screen: a tooltip beside a button, a menu under a menubar item, a submenu beside its parent row, a completion list next to a caret, a hover card beside a link, a teaching tip beside a feature. Thirty-eight systems were read at pinned revisions to answer one question — how much of that problem is surface-independent? — because sparkles:ui must solve it once, in integer cells, for a GPU window, a terminal cell grid, a script-free HTML page and an Android NativeActivity, none of which agree on whether hover exists, whether a key release arrives, whether there is a frame clock, or whether there is an OS window at all.

The corpus was chosen to make the surface question falsifiable rather than assumed. It spans a wire protocol whose placement runs in another process (xdg_positioner), a browser engine (Blink), ten desktop toolkits, three mobile stacks, ten headless web libraries, and ten terminal systems that have no compositor, no hover and no timers — plus the one historical subject (Turbo Vision) that already built the whole vocabulary inside a character grid in the early 1990s. Where the field's answers diverge, the divergence is reported as a fork rather than resolved by preference; where a first-pass claim did not survive verification, the narrower wording is what appears in the tree.

This survey answers ten questions

  1. What is the minimal surface-independent core? — six values and pure functions over them, with a short, explicit list of what is irreducibly surface-specific. Vocabulary in concepts.md.
  2. Can placement be a pure function of Regular values? — yes, with two amendments the verification pass forced; demonstrated by place-reference.d.
  3. What does the cell grid actually cost? — which behaviours degrade gracefully, which degrade badly, and which are simply unrepresentable in whole cells. Per-target constraints in sparkles-baseline.md.
  4. What replaces hover? — on targets with no pointer, and on targets where hover exists but warm-up has no clock. Timing behaviours catalogued in features-people-forget.md; the machine is tooltip-timing.d.
  5. What does a script-free HTML target get? — what survives when the only runtime is the cascade, read against CSS anchor positioning and the Popover API.
  6. How much of Floating UI will the browser absorb? — which of the middleware set the platform has already taken, and which parts it structurally cannot.
  7. Overlay tree, or overlay list? — why the tree must be a query over a flat ordered list, not a structure. Layering vocabulary in concepts.md.
  8. Where does adaptive presentation belong? — popover-versus-sheet-versus-dialog as a host decision above the primitive, on Apple's and WinUI's evidence.
  9. What must the API not foreclose? — the decisions that are cheap now and unaffordable later, which is what proposal.md is built around.
  10. What should Sparkles build? — the final synthesis, taken up as a milestoned plan in proposal.md against the delta table in sparkles-baseline.md.

Last reviewed: August 14, 2026

IMPORTANT

Every claim in this tree is tied to a primary source at a pinned revision, recorded in the revision ledger below. A citation is the upstream URL at that SHA — so any statement here can be re-checked against exactly the code that produced it, years from now. Load-bearing statements in comparison.md additionally passed a two-lens adversarial verification pass; statements that are analysis rather than observation are marked INFERENCE there.


Master catalog

Thirty-eight subjects. Surface model is the single most consequential column for this toolkit: OS popup means the overlay is a separate window the compositor or window manager owns; in-canvas means it is painted into the same surface as everything else — the constraint sparkles:ui works under; both means one declaration resolves to either at runtime, which is the interesting case, because it proves the two share a core.

SubjectCategoryWhere the behaviour livesSurface modelDeep-dive
Floating UIWeb / headless positioningA ~100-line kernel folding an ordered middleware array over one tuple, behind a three-method Platformin-canvas (coordinates only; the top layer is detected, never entered)floating-ui.md
Radix PrimitivesWeb / headless behaviourFour separately-consumable mechanisms: Popper, DismissableLayer, FocusScope, Portalin-canvas (React portal into document.body; no top layer)radix.md
Base UIWeb / headless behaviourOne ~800-line positioning hook plus one reason-tagged popup store shared by ten componentsin-canvas (DOM only; no showPopover, no dialog)base-ui.md
AriakitWeb / headless behaviourA single-inheritance chain of stores and prop-transformer hooks; a 96-line polygon test in-housein-canvas (React portal into document.body)ariakit.md
Zag.jsWeb / state machinesA statechart as inert data plus one single-purpose package per concern (popper, dismissable)in-canvas (content portalled to document.body)zag.md
Headless UIWeb / headless behaviourA pure-reducer Machine plus a forty-line stack machine; no positioner and no arrow, deliberatelyin-canvas (one userland portal root, an explicitly non-native "top layer")headlessui.md
Floating VueWeb / framework bindingOne 1187-line Popper.ts; tooltip, dropdown and menu are nine-line files differing by a theme stringin-canvas (one container, one flat z-index: 10000)floating-vue.md
Tippy.jsWeb / imperative controller1145 lines of when — timing, intent and lifecycle — configuring Popper 2 for the wherein-canvas (a div in the same document; z-index: 9999)tippy.md
Angular CDK OverlayWeb / enterprise managerOverlayRef + FlexibleConnectedPositionStrategy + a scroll strategy + one document-level key/pointer stackboth — legacy .cdk-overlay-container div; since v22 the browser top layer by feature testangular-cdk.md
React AriaWeb / headless behaviourA hand-written ~850-line calculatePosition plus a document-global tooltip warm-up machinein-canvas (DOM portal into document.body)react-aria.md
HTML Popover APIWeb platformSpec algorithms for stacking, cascade dismissal, focus scope and re-entrancy — and no geometry at allboth — the top layer is an in-document ordered set; the one OS surface is select's native pickerpopover-api.md
CSS Anchor PositioningWeb platformThe cascade: anchor(), anchor-name, position-try-fallbacks, and an incumbent-skip hysteresis rulein-canvas (the UA top layer is a paint-order set, not an OS popup)css-anchor.md
Chromium / BlinkWeb platform (impl)Two systems sharing one pointer: popover owns lifecycle, anchor positioning owns geometryin-canvas (Document::top_layer_elements_, a per-document vector)blink.md
WAI-ARIA APGWeb platform / a11yPatterns and six reference implementations: roles, focus ownership, dismissal, modality — no placementin-canvas (position: absolute inside the trigger's containing block)aria-apg.md
Qt Quick ControlsNative desktop (Qt)One QQuickPopup base class: a declaration plus a permission set (ClosePolicy, six placement booleans)bothqt-quick-controls.md
Qt WidgetsNative desktop (Qt)One window flag (Qt::Popup) buying the stack, the grab, event re-routing and modality exemptionOS popupqt-widgets.md
GTK4Native desktop (GTK)GdkPopupLayout — a ten-scalar value — plus a swappable solver (compositor, GDK arithmetic, or Android)both — a compositor surface everywhere except the Android backend, which clips to the parentgtk4.md
WPFNative desktop (Windows)Candidate generation plus scoring in PlacementMode/CustomPopupPlacement, one HwndSource per popupOS popup (WS_POPUP + WS_EX_TOPMOST + WS_EX_NOACTIVATE)wpf.md
WinUINative desktop (Windows)Two stacks sharing a portal and a dismissal layer: CPopup/FlyoutBase, plus TeachingTip's forked 14-candidate solverbothwinui.md
Uno PlatformNative desktop/web (.NET)Every open popup is a full-window Panel under one in-app PopupRoot; placement is managed Rect arithmeticin-canvas (plus one Android full-screen native window contributing no placement)uno.md
AvaloniaNative desktop (.NET)ManagedPopupPositioner — a ~130-line solver modelled on xdg_positioner — behind two adaptersboth — the same solver serves a PopupRoot window and an in-window OverlayPopupHostavalonia.md
SlintNative desktop (Rust)One point anchor, one clamp-and-shrink pass, a flat stack of extra item trees; policy pushed into .slintboth — an in-window ChildWindow, a real OS child window, or a native OS menuslint.md
Zed / GPUINative desktop (Rust GPU)A flat per-frame vector of deferred paint records; anchored() elements; no top layer, no grabin-canvas (one OS window, one GPU surface)gpui.md
Dear ImGuiImmediate-mode GUITwo flat POD arrays, one ~70-line integer placement function, one draw-layer bitin-canvas (every popup is an ordinary ImGuiWindow in the same ImDrawData)imgui.md
Jetpack ComposeMobile / adaptive (Android)PopupPositionProvider.calculatePosition(anchorBounds, windowSize, layoutDirection, contentSize)IntOffsetOS popup (a real WindowManager child window per popup)compose.md
FlutterMobile / adaptiveOverlayPortal / RawMenuAnchor / PopupRoute in one render tree; positionDependentBox for tooltipsin-canvas (one render tree, one surface; SystemContextMenu on iOS is the one escape hatch)flutter.md
Apple (UIKit/AppKit/SwiftUI/TipKit)Mobile & desktopNine overlapping primitives across four frameworks, sharing a content model but never an anchor or a policyboth — NSPopover/NSMenu are OS surfaces; UIPopoverPresentationController is an in-window presentationapple.md
Wayland xdg_positionerProtocol-level algebraA ~40-byte POD of plain ints solved out of process by the compositorOS popup (a compositor-managed wl_surface with the xdg_popup role)xdg-positioner.md
HelixTerminal / cell gridOne ~60-line integer-cell function re-run from scratch every frame; a flat Vec of self-clipping paintersin-canvashelix.md
Neovim floatsTerminal / cell gridnvim_open_win: an anchor descriptor resolved to one cell, clamped; ui_compositor merges by zindexboth — a float is an in-canvas cell rectangle, but opaque to the plugin that opened itneovim-floats.md
NotcursesTerminal / cell gridThe ncplane — an independently owned cell buffer in a totally ordered ncpilein-canvas (one framebuffer; the terminal is the only surface)notcurses.md
nui.nvimTerminal / cell gridA declarative geometry vocabulary — {relative, position, size, anchor, border} — normalised by one functionin-canvas (Neovim floats; no collision engine at all)nui.md
nvim-cmp / blink.cmpTerminal / cell gridMenu-beside-a-text-range, then docs-beside-the-menu, on a pure integer grid with no pointerboth — floats are in-canvas cells, but opaque rect+zindex handles to the pluginnvim-completion.md
RatatuiTerminal / cell gridNo overlay primitive: a ten-line Clear widget, a Rect with clamp/intersection, and later-call-winsin-canvasratatui.md
TextualTerminal / cell gridThree CSS rules taught to the ordinary layout engine — layers/layer, overlay, constrainin-canvastextual.md
tmuxTerminal / cell griddisplay-popup / display-menu painted into the grid tmux already owns; three generations side by sidein-canvastmux-popup.md
Turbo VisionTerminal / cell grid (historical)A complete windowing system in TScreenCells: TView/TGroup, menus, submenus, modals, drop shadowsin-canvas (the console is the only surface)turbo-vision.md
Emacs posframe + companyTerminal / GUI hybridA poshandler: a named pure function of a flat measured record; plus a second, surface-free cell rendererboth — a child frame in GUI Emacs, an overlay-based pseudo-tooltip in a terminalemacs-posframe.md

Beyond the deep-dives, five synthesis documents:

DocumentWhat it is
concepts.mdThe shared vocabulary — anchor, placement, constraint adjustment, boundary, top layer, warm-up, safe polygon, grab, modality, geometry metadata — each defined once, with canonical spellings and an index of which subject exercises it
comparison.mdThe capstone: twelve capabilities × thirty-eight subjects, sixteen dimensions with a best-in-class per dimension, the consensus, the genuine forks, and the ten questions
features-people-forget.mdThe behaviours nobody remembers until they ship — anchoring, collision, timing, pointer intent, dismissal, focus, layering, accessibility, animation, degradation
sparkles-baseline.mdWhat sparkles:ui can express today: WidgetKind.popup, the Palette popup metrics, clampOrigin, HoverPopup, DCK5, the open defects, the per-target constraint list, and the delta table
proposal.mdThe milestoned plan: the primitive architecture, the bands-versus-precedence resolution, an API straw man, the state machines, the geometry pipeline, the adapter surface, and the open questions

And three runnable examples that CI compiles and runs, so the conclusions cannot rot:

ExampleThe claim it pins
place-reference.dplace() as a @safe pure nothrow @nogc function over Regular values returning a decision record, not a point
tooltip-timing.dThe warm-up / cool-down machine as one shared arbiter holding two integers, composed from the existing Timeline
dismissal-policy.dDismissal as one value: a policy flags word ANDed with a router-offered cause

Revision ledger

Every subject, the upstream repository, and the exact revision it was read at. This is what makes the tree re-verifiable: a claim on any page can be checked against precisely this code. SHAs are given in full and are never abbreviated.

SubjectRepositoryRevision readDate read
Dear ImGuiocornut/imgui46d39d56febc2a00bdd2270dc88c8a13f2a0441a2026-08-11
Apple (UIKit/AppKit/SwiftUI/TipKit)developer.apple.comdocs-only — no public source (reference pages as published August 2026)2026-08-11
Jetpack Composeandroidx/androidx268d841a45644cadf438fc335c793869728449ec2026-08-11
Flutterflutter/flutterfeab40b83b8d1954106e83bb1d7b52265a41cb452026-08-11
AvaloniaAvaloniaUI/Avaloniaaee3f68551b0ac4417e32996a6627f34462edbc32026-08-11
GTK4GNOME/gtk817caae3dd5bc8ff6f4a96d5bef0aa0dc0bec671 (GTK 4.23.1)2026-08-11
Qt Quick Controlsqt/qtdeclarativeffc46f28ab21b6666dbea46c81cf2726ce6824192026-08-11
Qt Widgetsqt/qtbased0787745aa43e5baf49de876f917946df6aceca52026-08-11
Zed / GPUIzed-industries/zedd71f1461045c098dc6ca6b1b5adcf1b8949722e82026-08-11
Slintslint-ui/slint24318cebc2b3feed4f7187e237915f52715ce2852026-08-11
WPFdotnet/wpf99caccf23145777f910711b51961885bec7832132026-08-11
WinUImicrosoft/microsoft-ui-xaml29ebf098f70df518b57b754130bc94004be8c6bc (winui3/main)2026-08-11
Uno Platformunoplatform/unodf5d18a850248cb8c2ccb34032b4ebeb54dc82832026-08-11
Wayland xdg_positionerwayland/wayland-protocolsafb614d5fcbd02d261a6ae91920aa91cf3915a8a (wayland-protocols 1.49)2026-08-11
Emacs posframe + companytumashu/posframe + company-mode/company-modeposframe 74c8c56131ed866db47ae4191364b72dd4852456 (v1.5.2, 2026-05-27); company-mode 1cc907ac9e46ae4209eb5a341131787e0c678406 (1.1.0, 2026-07-21)2026-08-11
Helixhelix-editor/helix14d6bc0febed9c692048271a8ae2362ac969c6e02026-08-11
Neovim floatsneovim/neovim2757f6eef92a99812d5ad12408d03592bd54f10c2026-08-11
Notcursesdankamongmen/notcursesb26048eebc74d5d254717d3332fa484718f9efe62026-08-11
Ratatuiratatui/ratatuia2ca2df5688772baffb743b494761f4ec82b31742026-08-11
TextualTextualize/textual06dbeef4bb70fb718236aa418ed658ef4667a1262026-08-11
nui.nvimMunifTanjim/nui.nvimde740991c12411b663994b2860f1a4fd0937c1302026-08-11
nvim-cmp / blink.cmpSaghen/blink.cmp + hrsh7th/nvim-cmpblink.cmp 8ca29c2eb34f5ce4770bffc0d62e6f636a4e8526 (2026-08-08); nvim-cmp 2ffe79f1f021def8dd1fcd81deb16f1bb0d989f3 (2026-07-10); corroborated against neovim 2757f6eef92a99812d5ad12408d03592bd54f10c2026-08-11
tmuxtmux/tmux851c5a933d4838c32ad06c248b2ba975d106149c (next-3.8)2026-08-11
Turbo Visionmagiblot/tvision57b6f56b38e0ee75240a80a10ee0e11470c246932026-08-11
Angular CDK Overlayangular/componentsf3e6276c969f33e527b616ef8bf7b0404685721d2026-08-11
Floating VueAkryum/floating-vue19857764c4f73dea7ed44a7d970adb968ee7ad902026-08-11
Ariakitariakit/ariakita0426ed547d95b84c9d53033053e51baeaca4aaa2026-08-11
Base UImui/base-uiadbd590484b26c1e68049348c57c70998ad667a72026-08-11
Headless UItailwindlabs/headlessuieea57cf46fd6767ed1059012f7073b88eb159fba (@headlessui/react 2.2.10)2026-08-11
Radix Primitivesradix-ui/primitivesf7ecd5ab16f5e1e820eb5786a1419a98a2d594ae2026-08-11
React Ariaadobe/react-spectrum7c0765468a1d161ab9ac88ca9f1b54d3603a275c2026-08-11
Floating UIfloating-ui/floating-ui0eb8c985a6d7aadc3fbe621acfc3d7f1cdd6fdf1 (@floating-ui/dom 1.8.0)2026-08-11
Tippy.jsatomiks/tippyjsad85f6feb79cf6c5853c43bf1b2a50c4fa98e7a1 (v6.3.7)2026-08-11
Zag.jschakra-ui/zageabc04440baa219723bc5d9a51d4e95c1deaf0242026-08-11
CSS Anchor Positioningw3c/csswg-drafts6dc15cc9cb15043840eacf081e89f5a666fa78892026-08-11
HTML Popover APIwhatwg/htmlac0389a3aca0331055bf4bf23f509c2913e3f7952026-08-11
Chromium / Blinkchromium/srcb0e30a9973232cee28901ea5d6cd4de6ea9428aa2026-08-11
WAI-ARIA APGw3c/aria-practices7e4034b262bc0d25332e330d8a582aaf341138292026-08-11

NOTE

Two subjects are specification readings rather than implementation readings (xdg_positioner and CSS Anchor Positioning), and one (Apple) is documentation-only because no source is published. Each page says so in its own header and marks every claim accordingly. Blink was read through a sparse checkout, so its legacy select popup-menu path is outside the reading.


Taxonomy

The same thirty-eight subjects, re-cut one axis at a time.

By surface model

The axis that decides how much of the field transfers to a single-surface toolkit. The both row is the load-bearing one: eleven subjects run the same placement code on an OS surface and on an in-window one, which is the strongest available evidence that placement is surface-independent.

Surface modelSubjectsCount
OS popup — a compositor/WM-owned surfaceCompose, Qt Widgets, WPF, xdg_positioner4
Both — one declaration, either surface at runtimeAngular CDK, Apple, Avalonia, GTK4, Neovim, nvim-cmp / blink.cmp, posframe + company, Popover API, Qt Quick Controls, Slint, WinUI11
In-canvas — painted into the surface it sharesAriakit, Base UI, Blink, CSS anchor, Dear ImGui, Floating UI, Floating Vue, Flutter, GPUI, Headless UI, Helix, Notcurses, nui.nvim, Radix, Ratatui, React Aria, Textual, Tippy, tmux, Turbo Vision, Uno, WAI-ARIA APG, Zag23

By placement algorithm family

Six families of candidate generation. Per comparison.md § 2, every one of them is integer arithmetic over four rects and a small policy value — the families differ on how candidates are produced, not on what they compute.

FamilySubjectsCount
Per-axis adjustment bits — a flags mask; no candidate combinatoricsxdg_positioner, GTK4, Avalonia, Qt Quick Controls, Slint, Textual6
Ordered candidate list — a fallback array, first fit winsFloating UI, Radix, Base UI, Ariakit, Zag, Floating Vue, Tippy, Headless UI (delegated), CSS anchor, Blink, WinUI, Uno, Compose, Dear ImGui14
Scored candidates — a real objective (visible area), with a total orderAngular CDK, WPF2
Single-candidate flip-then-clamp — exactly one alternative, then clampQt Widgets, React Aria2
Free-space budget — pick a side by room, hand that room to layout as a budgetHelix, Neovim, nvim-cmp / blink.cmp, GPUI, Flutter, tmux6
No solver — clamp-only, caller-supplied, or deliberately out of scopeApple (unpublished/system-owned), posframe + company (a caller-selected pure poshandler), Notcurses, Ratatui, nui.nvim, Turbo Vision, WAI-ARIA APG, Popover API8

By dismissal model

Who decides that a press landed "outside", and who owns the cause vocabulary. Values follow the comparison.md at-a-glance matrix; the mechanics are in comparison.md § 8 and concepts.md § 8.

Dismissal modelSubjectsCount
Substrate-delivered — the grab, the compositor or the UA decidesGTK4, Popover API, Blink, Apple, xdg_positioner5
Library-owned and on by defaultRadix, Base UI, Ariakit, Headless UI, Floating Vue, Tippy, React Aria, Qt Quick Controls, Qt Widgets, WPF, WinUI, Uno, Avalonia, Slint, GPUI, Dear ImGui, Compose, Flutter, Textual, tmux, Turbo Vision, posframe + company22
Opt-in packageFloating UI (@floating-ui/react's useDismiss)1
Partial — present but restricted or divergent between pathsZag, WAI-ARIA APG, Helix, Notcurses4
Caller's problem — the seam is exposed and nothing is decidedAngular CDK, Neovim, nui.nvim, Ratatui4
AbsentCSS anchor (out of scope by design), nvim-cmp / blink.cmp2

NOTE

The single best-shaped answer in the corpus is Qt Quick Controls' ClosePolicy plus tryClose(pos, phase) — a flags word ANDed with a cause the router supplies in the same vocabulary the policy is written in. Uno and WinUI reached the same shape independently and it rotted into verified dead code for want of a caller. dismissal-policy.d is that design in D.

By state architecture

Per comparison.md § 15, only four of thirty-eight model the open/close lifecycle as an explicit machine. Rows 3 and 4 are techniques and can co-occur with rows 1–2; row 5 is the residual.

State architectureSubjectsCount
Explicit lifecycle machineZag (declarative statechart), Headless UI (pure reducer, total dispatch), GPUI (tooltip enum), Compose (sealed context-menu status)4
Mount / transition lifecycle onlyRadix (three-state presence), Qt Quick Controls (transition state), Base UI (transition status)3
Openness as membership in one ordered array — no per-overlay booleanDear ImGui (compare two stack lengths), Popover API + Blink (the popover stack), Slint (monotonically-keyed vector), Headless UI (forty-line stack machine)5
Transactional value update — copy, modify, replace; restore on validation failureNeovim (key-presence-guarded partial config patches), xdg_positioner (normatively pinned copy-on-use), tmux (preferred beside current geometry)3
Loose booleans over an imperative controller — the rest of the catalogAngular CDK, Apple, Ariakit, WAI-ARIA APG, Avalonia, CSS anchor, Floating UI, Floating Vue, Flutter, GTK4, Helix, Notcurses, nui.nvim, nvim-cmp / blink.cmp, posframe + company, Qt Widgets, Ratatui, React Aria, Textual, Tippy, Turbo Vision, Uno, WinUI, WPF24

By whether the overlay can escape its parent's bounds

The unclippability question. It is what OS popups are bought for — and the third row is the proof that a survey of "how do I escape a clip" is not the same survey as "where does the box go", because three subjects place overlays perfectly well while never escaping anything.

EscapeSubjectsCount
Escapes the application window — onto the desktop, past every app-owned edgeApple, Avalonia (in its PopupRoot configuration), Compose, GTK4 (every backend but Android), posframe + company (GUI child frames), Qt Quick Controls, Qt Widgets, Slint (its TopLevel and native-menu paths), WinUI, WPF, xdg_positioner11
Escapes every in-app clip, bounded by the app/terminal surfaceAngular CDK, Ariakit, Base UI, Blink, CSS anchor, Dear ImGui, Floating Vue, Flutter, GPUI, Headless UI, Helix, Neovim, Notcurses, nui.nvim, nvim-cmp / blink.cmp, Popover API, Radix, React Aria, Textual, Tippy, tmux, Turbo Vision, Uno, Zag24
Clipped by an ancestor, or the subject does not answerWAI-ARIA APG (position: absolute inside the trigger's containing block — no portal anywhere in the corpus), Floating UI (emits coordinates; escaping is the caller's job), Ratatui (a widget can only write inside its own Rect)3

NOTE

Textual is the one subject that implements a genuine first-class top layer in integer cells with no OS window and no z coordinate, and it decomposes into exactly three resets: an order reset, a clip reset, and an extent reset that keeps a wide overlay from growing its host's scrollable size. The third appears in no other subject.


Milestones

When the capabilities the field now takes for granted actually landed. The Verified column is strict: ✓ means the fact and its date were read at the pinned revision recorded in the ledger; ⚠ means the fact is grounded but the calendar date comes from ecosystem knowledge outside the reading, and should be treated as approximate.

WhenMilestoneSubjectVerified
≈1990The whole overlay vocabulary — dropdown menus, cascading submenus, context menus, modal dialogs, a combobox surface, drop shadows — already exists inside a character cell grid, with no compositor, no hover, no key releases and no timersTurbo Vision⚠ era attribution; the tree read is magiblot/tvision, a modern port, and carries no such date
2006 (WPF 3.0)BetweenShowDelay — the cool-down / skip-delay as one duration plus one flag, defaulting to 100 msWPF⚠ "shipping since WPF 3.0" is read at the pinned revision; the calendar year is not
≈2016 (xdg-shell stable)set_constraint_adjustment makes flip/slide/resize a wire-level bitfield the client cannot compute, solved out of processxdg_positioner⚠ date not established at the pinned revision; what is pinned is that the last functional change was interface version 3, and the interface stands at version 7 in wayland-protocols 1.49
≈2020 (GTK 4.0)GtkPopover becomes a GtkNative with its own GdkSurface, and GdkPopupLayout becomes the ten-scalar value a compositor or GDK's own integer solver executesGTK4⚠ the 4.0 attribution was not read at the pinned revision (4.23.1)
≈2020 (Popper 2 → Floating UI)Placement becomes an ordered middleware fold over one mutable (x, y, placement, rects, middlewareData) tuple, with every environment contact behind a three-method PlatformFloating UI⚠ dates; the packages read are @floating-ui/dom 1.8.0 / @floating-ui/react 0.27.20
≈2023–2024The HTML Popover API and the top layer specify stacking, cascade dismissal, focus scope and re-entrancy in painstaking detail — and specify placement, timing, hover and semantics not at allPopover API, Blink⚠ shipping dates were not read; the algorithms were
≈2024CSS anchor positioning puts placement into the cascade — anchor(), position-try-fallbacks, and an incumbent-skip rule that trades optimality for stabilityCSS anchor⚠ ship date; at the pinned revision Level 1 is a Working Draft with Work Status "refining"
March 2020 → January 2026Ratatui's Clear — the one widget whose purpose is popups — panics when its rect crosses the right or bottom edge, for six yearsRatatui
April 2025Ratatui absorbs the centered_rect helper out of an example and into Rect, five years after it appearedRatatui
August 2025Ariakit patches tabindex across three separate open paths in one commit (ccfa79e8) — the cost of an overlay family with no single open funnelAriakit
December 2025CSS anchor-name lookup is re-specified to match timeline-name lookup (nearest ancestor first, else last match in tree order)CSS anchor
2026-04-28The ::tether pseudo-element — the arrow primitive — is reverted back out of the anchor-positioning drafts (31491a8b4), leaving Level 1 with no arrow concept at allCSS anchor
GTK 4.22GtkPopoverBin lands as the dedicated context-menu containerGTK4✓ version; ⚠ calendar date
Angular CDK v22The overlay's default layering becomes the browser top layer (popover="manual" + showPopover()), chosen once at creation by a feature testAngular CDK
notcurses 3.0.9The ncplane_move_family_* reconciliation stops looping forever — evidence that reconciling an ownership tree with a z-order is genuinely hardNotcurses✓ version; ⚠ calendar date
tmux next-3.8Three successive generations of the popup idea sit in the tree at once, with the maintainer's written verdict on the oldesttmux
posframe 1.5.2 (2026-05-27), company 1.1.0 (2026-07-21)The poshandler — placement as a named pure function of a flat measured record — paired with a second, surface-free renderer for the terminalposframe + company

WARNING

Entries marked ⚠ are not re-verifiable from this tree. They are included because a timeline with only the dates that happened to be committed to source comments would misrepresent the field's shape — but any of them should be re-checked before being quoted as fact.


Quick navigation

Reading paths

"I have twenty minutes." concepts.md for the vocabulary → comparison.md at a glance for the twelve-capability matrix → the ten questions.

"I am designing the Sparkles primitive this informs." The intended path, in order:

  1. sparkles-baseline.md — what sparkles:ui can express today: WidgetKind.popup as a look with no behaviour, the unfinished Palette popup metrics, clampOrigin/effectivePopupWidth as the entire current placement engine, the GUI-only HoverPopup, DCK5's finished overlay view with nowhere to live, the open defects, and the per-target constraint list.
  2. comparison.md § the ten questions — especially Q1 (the minimal core), Q2 (placement as a pure function), Q3 (what the cell grid costs) and Q9 (what not to foreclose).
  3. comparison.md § the genuine forks — the decisions the field does not agree on, which are therefore decisions rather than defaults.
  4. features-people-forget.md — read before freezing any signature; it is the list of behaviours that are cheap to design in and expensive to retrofit.
  5. proposal.md — the milestoned plan, then its open questions.
  6. The three examples: place-reference.d, tooltip-timing.d, dismissal-policy.d — the conclusions as code CI runs.

"I am writing the placement solver." GTK4 (best in class: complete, pure integer, per-axis, value-shaped) → xdg_positioner (the same algebra proven across a process boundary) → Angular CDK (runner-up: a total order over candidates) → comparison.md § 2 and § 3place-reference.d.

"I am writing tooltip timing." WPF (BetweenShowDelay, the original formulation) → React Aria (the document-global warm-up machine) → concepts.md § warm-up / cool-downfeatures-people-forget.md § Timingtooltip-timing.d.

"I am writing dismissal, focus and modality." Qt Quick Controls (policy as data) → Popover API + Blink (the cause set and the cascade) → Flutter (the hit-group test with no grab) → comparison.md § 8dismissal-policy.d.

"I am on a cell grid and want to know what survives." Textual (a real top layer in integer cells) → Turbo Vision (the whole vocabulary, thirty-five years early, and the substitute-don't-omit rule) → Helix and tmuxcomparison.md Q3.

"I care about accessibility and the a11y tree." WAI-ARIA APG (roles, focus ownership, dismissal, modality) → Applefeatures-people-forget.md § Accessibilitycomparison.md § 13.

Neighbouring trees

TreeWhat it carries that this one does not
Window system integrationThe compositor grab, the X11 override-redirect alternative, and the in-canvas fork as a windowing decision
Platform UI guidelinesThe platform conventions an overlay's chrome must respect — appearance, contrast, accent, motion
UI layoutThe box-flow model an overlay's content is laid out by
Sean Parent: Better CodeThe value-semantics vocabulary the recommendations lean on — Regular types, local reasoning, narrow contracts
TUI librariesThe cell-grid rendering substrate the terminal subjects sit on

Specs this survey is tested against

UI principles (PRN1PRN12) · state machines (STM1STM13) · the input model (the tier ladder, the hit-testing model) · container routing precedence (DCK13's empty top-layers rung, and DCK5) · backend degradation (TGT5) · the widget catalog (WGT7's popup, WGT16's toast) · the theme.


Sources