feat(search): shared keyboard navigation + ARIA for search bars (LC-157 phase 1) #209
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-157-search-keyboard-nav"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Phase 1 of LC-157 (unify search). The four generic search bars (sidebar people / messages, enclave invite, group add-members) already shared an identical HTMX debounce/fetch/swap; the real gap the audit flagged was no keyboard navigation and no listbox/option ARIA. Their result item semantics genuinely differ (two navigate via links, two submit inline forms), so this layers one shared interaction over the existing searches rather than rewriting each endpoint's result rendering into a single fragment shape.
How
assets/search.js: an input opts in withdata-lc-search+data-lc-search-results="#container". The module adds ArrowUp/ArrowDown over the[role=option]items (managesaria-activedescendant+ a highlight), Enter to activate the highlighted option (clicks it if it is a link/button, else the first link/button inside - so a row's navigation anchor or its Invite/Add form submit both work), and Escape to clear. HTMX still owns the fetch;htmx:afterSettlereflectsaria-expandedand clears the stale highlight. Loaded once with delegated listeners, so it survives result swaps.role="listbox"on the wrapper androle="option"+ a unique id per item; the four inputs gain thedata-lc-searchattrs + combobox ARIA.Deferred (sub-issue)
The composer mention combobox already has full ARIA; folding in the slash-command popover (no keyboard nav today) + deeper consolidation.
Test
just check(templates compile), targeted route/db tests for the affected searches (routes_enclave, routes_user_groups, db_search) all green;just build-cssregenerates the highlight utility. JS keyboard behavior is not unit-tested in this repo (consistent with the existing untested composer combobox JS); the change is additive and preserves the existing HTMX fetch.Part of the LC-159 post-audit story.
🤖 Generated with Claude Code
Review follow-up: option ids were lc-opt-{user_id}, which collides when several search lists render on the same page - the sidebar people/message searches coexist with the main page's invite/group searches, and the enclave settings page renders one add-member search per group (the same user can appear in several). Duplicate ids make aria-activedescendant resolve to the first matching element in the document, so a screen reader announces the wrong option (navigation itself was already container-scoped and unaffected). Namespace per search: lc-opt-people-/-msg-/-invite-/-group-{group_id}- so every option id is unique across the document. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>