feat(a11y): keyboard navigation for the slash-command popover (LC-168) #213

Merged
nrupard merged 1 commit from feat/lc-168-slash-keyboard-nav into main 2026-05-26 16:38:29 +02:00
Owner

What

LC-168: give the slash-command popover keyboard navigation, matching the mention combobox (the two live in the same composer; mention already had a full WAI-ARIA pattern, slash was click-only).

How

  • Mirror the mention combobox's logic in the slash script: ArrowUp/Down move the active [role=option], Enter/Tab insert (reuses __lcInsertSlash), Escape closes; the textarea's aria-activedescendant tracks the highlighted option; htmx:afterSwap highlights the first option so Enter inserts a default without an arrow press first.
  • The slash popover options gain a stable id + aria-selected.
  • The two comboboxes share the composer textarea but are mutually exclusive (the slash regex requires the whole value be a single /command, so an @-mention token can't match at the same time), so the two keydown handlers never both act - the inactive one no-ops on its empty-token guard. Mouse click is unchanged.

Deeper consolidation

Added a main.css rule highlighting [role="option"][aria-selected="true"]. Both comboboxes set aria-selected on keyboard nav but nothing styled it, so the keyboard selection was screen-reader-announced yet visually invisible. This fixes it uniformly for slash, mention, and the LC-157 search bars.

Test

just check (templates incl. the updated fragment compile), routes_slash green (renders the popover with the new id/aria-selected). main.css is hand-written + served directly (no rebuild). JS keyboard behavior isn't unit-tested in this repo (consistent with the existing untested mention combobox JS); this mirrors that proven pattern.

Follows LC-157; part of the post-audit consolidation.

🤖 Generated with Claude Code

## What LC-168: give the slash-command popover keyboard navigation, matching the mention combobox (the two live in the same composer; mention already had a full WAI-ARIA pattern, slash was click-only). ## How - Mirror the mention combobox's logic in the slash script: ArrowUp/Down move the active `[role=option]`, Enter/Tab insert (reuses `__lcInsertSlash`), Escape closes; the textarea's `aria-activedescendant` tracks the highlighted option; `htmx:afterSwap` highlights the first option so Enter inserts a default without an arrow press first. - The slash popover options gain a stable id + `aria-selected`. - The two comboboxes share the composer textarea but are **mutually exclusive** (the slash regex requires the whole value be a single `/command`, so an `@`-mention token can't match at the same time), so the two keydown handlers never both act - the inactive one no-ops on its empty-token guard. Mouse click is unchanged. ## Deeper consolidation Added a `main.css` rule highlighting `[role="option"][aria-selected="true"]`. Both comboboxes set `aria-selected` on keyboard nav but nothing styled it, so the keyboard selection was screen-reader-announced yet **visually invisible**. This fixes it uniformly for slash, mention, and the LC-157 search bars. ## Test `just check` (templates incl. the updated fragment compile), `routes_slash` green (renders the popover with the new id/aria-selected). main.css is hand-written + served directly (no rebuild). JS keyboard behavior isn't unit-tested in this repo (consistent with the existing untested mention combobox JS); this mirrors that proven pattern. Follows LC-157; part of the post-audit consolidation. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(a11y): keyboard navigation for the slash-command popover (LC-168)
All checks were successful
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / TruffleHog (push) Successful in 6s
check-secrets / Kingfisher (push) Successful in 9s
check-secrets / TruffleHog (pull_request) Successful in 3s
check-secrets / Nosey parker (pull_request) Successful in 4s
check-secrets / Kingfisher (pull_request) Successful in 4s
Check / clippy + fmt + tests (pull_request) Successful in 1m33s
Create release / Create release from merged PR (pull_request) Has been skipped
bcf39e6901
The slash-command autocomplete was click-only; the mention combobox in the same composer already had a full WAI-ARIA keyboard pattern. Bring slash to parity by mirroring that logic: ArrowUp/ArrowDown move the active option, Enter/Tab insert it, Escape closes, and the textarea's aria-activedescendant tracks the highlighted option. The popover options gain a stable id + aria-selected; an htmx:afterSwap hook highlights the first option so Enter inserts a sensible default without an explicit arrow press first.

The two comboboxes share the composer textarea but are mutually exclusive (the slash regex requires the whole value be a single /command, so an @-mention token cannot match simultaneously), so the two keydown handlers never both act - the inactive one no-ops on its empty-token guard. Mouse click + __lcInsertSlash are unchanged.

Also adds a main.css rule highlighting [role="option"][aria-selected="true"]: both comboboxes set aria-selected on keyboard navigation but nothing styled it, so the keyboard selection was announced to screen readers yet invisible to sighted keyboard users. The rule fixes that for slash, mention, and the LC-157 search bars uniformly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
nrupard deleted branch feat/lc-168-slash-keyboard-nav 2026-05-26 16:38:29 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!213
No description provided.