Skip to content

fix(web): a11y escape + initial focus on relay popover#409

Merged
intendednull merged 1 commit into
mainfrom
claude/issue-352-relay-popover-escape
Apr 27, 2026
Merged

fix(web): a11y escape + initial focus on relay popover#409
intendednull merged 1 commit into
mainfrom
claude/issue-352-relay-popover-escape

Conversation

@intendednull
Copy link
Copy Markdown
Owner

Why

Relay-signal popover claims aria-haspopup="dialog" but keyboard users got stranded:

  • No Escape close. Global stack in keybindings::install does not know about this popover — Escape was a no-op while focus was inside.
  • No initial focus. Tab walked past the dialog content into page chrome.

Issue title says "focus trap" but body says non-modal. Trapping focus on a non-modal popover is wrong — would break Tab-out. Seed focus instead, mark aria-modal="false".

Fix

crates/web/src/components/relay_signal_button.rs:

  • Local on:keydown on .relay-popover — Escape sets open=false, stops propagation so global handler does not double-fire.
  • Effect on open transition pulls focus to settings-link button via NodeRef + request_animation_frame (same pattern as ConfirmDialog).
  • aria-modal="false" + tabindex="-1" on the dialog so it can take focus and AT knows it is non-modal.

No focus trap — Tab continues out of the popover normally.

Verify

  • cargo fmt --check clean
  • cargo clippy --workspace --all-targets -- -D warnings clean
  • cargo check -p willow-web --tests --target wasm32-unknown-unknown clean (Firefox + geckodriver not installed in this env, so wasm-pack browser run is deferred to CI; compile coverage proves the new tests build)
  • cargo test -p willow-web --lib 72 passed
  • New wasm-pack tests in crates/web/tests/browser.rs:
    • relay_signal_button_escape_closes_popover — opens popover, dispatches Escape keydown, asserts popover unmounts + aria-expanded="false"
    • relay_signal_button_focuses_settings_link_on_open — opens popover, waits one frame, asserts document.activeElement is the settings-link button
    • relay_signal_button_popover_is_non_modal — asserts aria-modal="false" + role="dialog"

Closes #352


Generated by Claude Code

Popover advertises `aria-haspopup="dialog"` but had no Escape handler
and no focus pull. Global keybinding stack does not own this popover —
local listener required. Seed focus on settings link so keyboard users
land inside the dialog. Mark `aria-modal="false"` — popover does not
trap focus.

Tests: Escape closes, settings link focused on open, aria-modal="false".

Closes #352
@intendednull intendednull merged commit 00aa515 into main Apr 27, 2026
7 checks passed
@intendednull intendednull deleted the claude/issue-352-relay-popover-escape branch April 27, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GEN-09] RelaySignalButton popover lacks Escape handling and focus trap

2 participants