fix(tooltip): dismissible + hoverable per WCAG 1.4.13#3363
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR No new or modified components detected. Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
Adds Escape-to-dismiss (IME-guarded) and a hover bridge so the pointer can travel from the trigger onto the tooltip surface without it vanishing. useLayer context render props gain onMouseEnter/onMouseLeave on the container.
9dd4e9a to
6887995
Compare
30 tasks
cixzhang
commented
Jul 2, 2026
| // `layer.isOpen` (React state, which can lag a frame behind the DOM) — | ||
| // `layer.hide()` self-guards and no-ops when the layer is already closed. | ||
| // Guarded against IME composition-cancel. | ||
| useEffect(() => { |
Contributor
Author
There was a problem hiding this comment.
I'm seeing this in a few different PRs plus we want to ensure that only top layer gets dismissed before cascading to other layers. We should coordinate these in a followup.
josephfarina
approved these changes
Jul 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of the accessibility & keyboard-management program (#3343). Fixes finding
overlays-5(Tooltip WCAG 1.4.13).Problem
Tooltipfailed both prongs of WCAG 1.4.13 (Content on Hover or Focus):Escapehandler anywhere inuseTooltip, so a keyboard user who focused a trigger could not dismiss the tooltip without moving focus away.mouseleaveon the trigger hid the tooltip at the defaulthideDelayof0, with no listeners on the tooltip surface — so the pointer could not travel across the gap onto the tooltip content to read or interact with it.Fix
keydownlistener hides the tooltip onEscapewhile it is uncontrolled. Guarded against IME composition-cancel (isComposing/keyCode === 229).layer.hide()self-guards, so this is a no-op when the tooltip is already closed.100mswhen no explicithideDelayis set) plusonMouseEnter/onMouseLeavehandlers on the tooltip container keep the tooltip open while the pointer is over it. These handlers are attached to the layer container itself (the element the user hovers), not the inner content div, becausemouseenter/mouseleavedo not bubble.useLayerprimitive.ContextRenderPropsgains optionalonMouseEnter/onMouseLeaveso any hover-driven layer (Tooltip, HoverCard) can implement hoverable behavior through the shared primitive rather than reaching around it.Controlled tooltips (
isOpenprop set) are unchanged — their visibility stays owned by the consumer.Tests
Adds three
Tooltip.test.tsxcases: Escape dismisses while visible; Escape during IME composition does not dismiss; the tooltip stays open when the pointer moves onto the surface. Full suite green (10 Tooltip + 52 Layer/Popover/HoverCard), typecheck clean.