Skip to content

tooltip

Provenance

  • Source: .spec/spexcode/spec-dashboard/dashboard-ui/ui-primitives/tooltip/spec.md
  • Source SHA-256: 3777937db2fa301ee9bd2ef8a93a01f6d49afbbe7fd86fa664d03285896afef8

raw source

The dashboard's hover hints were all native title= — the browser's default yellow box: ugly, unstyled, blind to the app's light/dark theme, uncontrollable in timing and placement. A modern app draws its own tooltip. Replace the visual layer with one shared component; keep the accessibility layer (aria-label) untouched.

expanded spec

One singleton TooltipLayer (mounted once in the desktop shell) is the whole system. There is no per-callsite component: any element carrying a data-tip="…" attribute participates, so migrating a control is swapping title= for data-tip= — no restructuring, no wrapper. The layer delegates at the document level (pointerover/pointerout rather than mouse events, so even disabled buttons tip) and portals one bubble to <body>.

Behaviour, the modern contract:

  • Hover and keyboard focus both trigger. Hover arms a ~400ms intent delay (with a short warm window, so sweeping across a row of controls swaps tips quickly); keyboard :focus-visible shows immediately — a mouse click's focus stays quiet. Esc, scroll, resize, or any press dismisses.
  • Above by default, flips when clipped. The bubble centres over the anchor with a small arrow; when the viewport would clip it above, it flips below, and it clamps horizontally with the arrow still pointing at the anchor. Fade/slide transition in and out.
  • Theme-adaptive is a hard requirement. The bubble styles only through the palette CSS variables (--panel2 --ink2 --line) under [[dashboard-shell]]'s :root / :root[data-theme=<code>] scheme, so every theme preset renders a native-feeling bubble and a theme flip restyles it with zero component logic. No hardcoded colours.
  • Accessibility keeps both channels. Existing aria-labels stay (the visual tooltip only replaces the visual title=); while shown, the layer stamps aria-describedby on the anchor pointing at the role=tooltip bubble. Multi-line tips (\n joins) render as lines, not one blob.

The migrated surfaces are the interactive chrome: the [[side-nav]] rail, the HUD/help and action buttons, session pills/avatars/status glyphs, chips and badges across the node, evals, and issues views. The phone face keeps native title= (no hover there, and the layer mounts only in the desktop shell).