Skip to content

a11y(1.4.13): migrate saved-query nav tooltips to Tooltip primitive#3607

Open
rosanusi wants to merge 2 commits into
mainfrom
wcag/1.4.13-saved-query-tooltip-migration
Open

a11y(1.4.13): migrate saved-query nav tooltips to Tooltip primitive#3607
rosanusi wants to merge 2 commits into
mainfrom
wcag/1.4.13-saved-query-tooltip-migration

Conversation

@rosanusi

Copy link
Copy Markdown
Contributor

Summary

Replaces the hand-rolled JS-positioned tooltips in the saved-query nav rail (saved-query-views.svelte) and standalone-activities saved-views rail (saved-views.svelte) with the Holocene Tooltip primitive (PR #3429).

Each file maintained ~40 lines of custom positioning state and DOM logic that failed three SC 1.4.13 sub-criteria:

Sub-criterion Before After
Dismissible (Escape closes without moving focus) Fails — no Escape handler Passes — primitive's svelte:window keydown handler; dismissed flag auto-resets on leave
Hoverable (pointer can move from trigger onto tooltip) Fails — pointer crossing the wrapper boundary fired onmouseleave before reaching the position: fixed div Passes — primitive's 120 ms HOVER_HIDE_DELAY_MS + mouseenter on the popover cancels the hide timer
Persistent on focus Passes (post-2.1.1 fix) Passes — focusin/focusout in primitive
role="tooltip" (4.1.2) Fails — plain <div role="tooltip"> with no aria-describedby on trigger Passes — primitive wires aria-describedby on wrapper, role="tooltip" + id on popover

Net change: ~80 lines removed across two files; 18 lines added (Tooltip wrapper + import).

What changed

  • src/lib/pages/saved-query-views.svelte: removed showTooltip, tooltipText, tooltipX/Y, positionTooltipFrom, onQueryBtnEnter/Move/Leave, inline portal function, and floating <div use:portal>. Replaced wrapper <div> in queryButton snippet with <Tooltip text={…} right usePortal hide={$savedQueryNavOpen}>.
  • src/lib/components/standalone-activities/saved-views.svelte: same migration; text={view.name} (no task-failures special-casing needed here).

hide={$savedQueryNavOpen} preserves the existing gate: tooltip suppressed when the nav rail is expanded (full name already visible in the button label).

usePortal delegates positioning to the Portal/Floating-UI integration, replacing the manual getBoundingClientRect arithmetic and also closing the 1.4.4 fixed-pixel-width/zoom gap on the same surface.

Dependencies

Test plan

Keyboard:

  • Collapse the saved-query nav rail. Tab through query buttons. Tooltip appears on focus with full (untruncated) name.
  • Press Escape with tooltip visible. Tooltip dismisses without focus moving.
  • Tab to next button. New tooltip appears. Shift+Tab back — tooltip re-appears (dismissed auto-resets).

Pointer:

  • Hover a query button. Tooltip appears.
  • Move pointer diagonally onto tooltip content. Tooltip stays open (Hoverable criterion).
  • Move pointer off both. Tooltip closes.

Screen reader:

  • VoiceOver / NVDA: focus a query button. Tooltip text announced via aria-describedby.

Regression:

  • $savedQueryNavOpen = true (expanded rail): no tooltip appears.
  • Tab order unchanged — tabindex="-1" wrapper still skipped; inner <Button> is the focus stop.
  • Tooltip visually appears to the right of the trigger button, centered vertically.

References

A11y-Audit-Ref: 1.4.13-saved-query-hand-rolled-tooltip

🤖 Generated with Claude Code

Replaces the hand-rolled JS-positioned tooltip in saved-query-views.svelte
and standalone-activities/saved-views.svelte with the Holocene Tooltip
primitive (PR #3429).

Each file previously maintained ~40 lines of custom state and DOM
positioning logic (showTooltip, tooltipText, tooltipX/Y, positionTooltipFrom,
onQueryBtnEnter/Move/Leave, use:portal floating <div>) that failed three
SC 1.4.13 sub-criteria:

- Dismissible: no Escape handler
- Hoverable: pointer crossing the wrapper boundary fired onmouseleave
  before reaching the fixed <div>, dismissing the tooltip
- ARIA: plain <div role="tooltip"> with no aria-describedby on the trigger

The Tooltip primitive supplies all three:
- Escape-to-dismiss via svelte:window keydown (dismissed flag auto-resets)
- Hover bridge: 120 ms HOVER_HIDE_DELAY_MS lets the pointer transit
  onto the Portal-rendered popover; mouseenter on the popover cancels the
  hide timer
- aria-describedby on the wrapper <div>; role="tooltip" + id on the popover

hide={$savedQueryNavOpen} preserves the existing gate: tooltip is
suppressed while the nav rail is expanded (full name already visible).
usePortal delegates positioning to the Portal/Floating-UI integration,
replacing the manual getBoundingClientRect arithmetic and also closing
the 1.4.4 fixed-pixel-width gap on that surface.

Net: ~80 lines removed across two files; no new lines of tooltip logic added.

A11y-Audit-Ref: 1.4.13-saved-query-hand-rolled-tooltip

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jun 29, 2026 3:03pm

Request Review

@github-actions github-actions Bot added a11y Accessibility audit PR a11y:bucket-3 Bucket 3: engineer required a11y:sc-1.4.13 labels Jun 29, 2026
@temporal-cicd

temporal-cicd Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

📊 Strict Mode: 4 errors in 2 files (0.5% of 886 total)

src/lib/components/standalone-activities/saved-views.svelte (1)
  • L154:25: Argument of type 'string | undefined' is not assignable to parameter of type 'string | number | boolean'.
src/lib/pages/saved-query-views.svelte (3)
  • L341:10: 'view.count' is possibly 'undefined'.
  • L348:53: 'view.count' is possibly 'undefined'.
  • L152:25: 'activeQueryView' is possibly 'undefined'.

Generated by 🚫 dangerJS against a8e87c8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
class={merge(
'h-4 w-4 flex-shrink-0 transition-colors duration-200',
$savedQueryNavOpen ? 'lg:hidden' : '',
'flex w-full justify-start',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'view.count' is possibly 'undefined'.

disabled={view.disabled}
size="sm"
>
<Icon

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'view.count' is possibly 'undefined'.

@rosanusi rosanusi marked this pull request as ready for review June 29, 2026 15:12
@rosanusi rosanusi requested a review from a team as a code owner June 29, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11y:bucket-3 Bucket 3: engineer required a11y:sc-1.4.13 a11y Accessibility audit PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant