Let a tooltip linger, and tell the screen reader what it says

A plain tooltip vanished the instant the pointer left, where M3 keeps one for
1.5s and shows only one at a time — these are popover="manual", so nothing was
closing the last one. A rich tooltip's bubble was never associated with its
trigger at all, so the explanation it exists to give was never announced; the
script now writes aria-describedby (and aria-haspopup/aria-expanded when it is
persistent) onto the focusable control in the trigger slot, and again after a
morph. Plan step 18, actions.md ACT-22, ACT-25.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold
2026-09-14 06:13:14 +02:00
co-authored by Claude Opus 5
parent 56d82b71f3
commit 05236ecb3a
5 changed files with 77 additions and 19 deletions
@@ -15,6 +15,12 @@
action's `wire:click` too and resources/js/rich-tooltip.js keeps showing and hiding the
element on the page rather than one the morph took away.
resources/js/rich-tooltip.js points the trigger at the bubble with `aria-describedby`, and a
`persistent` one also carries `aria-haspopup="dialog"` and `aria-expanded`: the explanation is
the whole point of a rich tooltip, and without the association a screen reader reads only the
trigger's own label. The trigger arrives in a slot, so only script can find the element in it
that takes the focus.
RichTooltipTokens (androidx Compose Material 3, Apache-2.0): title-small subhead and body-medium
text in on-surface-variant, label-large actions in primary. --}}
+3 -2
View File
@@ -5,8 +5,9 @@
<x-tooltip text="Copy link"><button ></button></x-tooltip>
It shows after a short hover on a pointer that can hover, at once on keyboard focus, and
hides on leave, blur, press and Escape. A phone has no hover, so a control there carries its
It shows after a short hover on a pointer that can hover, at once on keyboard focus, and hides
at once on a press or Escape; leaving or blurring lets it stand for M3's 1.5s. Only one
tooltip is on screen at a time, as M3 asks. A phone has no hover, so a control there carries its
words. The bubble is a `popover="manual"` in the top layer — never clipped by an
`overflow-hidden` parent, never widening a scroll container — placed by CSS anchor
positioning on `side` (`top`, `bottom`, `left`, `right`), flipping when there is no room.