Use a native <dialog> for the search modal - #2031
Merged
Merged
Conversation
Swap the div role="dialog" and hand-rolled Tab trap for a <dialog> opened
with showModal(), matching ShortcutsModal. The browser now handles focus
containment, inertness, and the ::backdrop; a close-event handler resets
state and returns focus to the trigger however the dialog closes.
Move the live region off #search-results so screen readers stop re-reading
the whole list on each keystroke; a visually hidden role="status" element
announces only the count ("5 results", "No results").
Export the rendering and navigation helpers and cover them with Vitest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
What
The search modal was a
div role="dialog"with a hand-rolled Tab trap. It's now a native<dialog>opened withshowModal(), following the patternShortcutsModalalready uses.::backdrop. The manualtrapFocushandler and its focusable-selector list are gone.closeevent handler resets the input, results, and scroll lock, and returns focus to the trigger. It runs however the dialog closes: Esc, ⌘K, the close button, a backdrop click, or a result click.@starting-styleplusallow-discrete, and falls back to no animation where unsupported.display: flexis scoped to[open]so it can't override the UA's hidden state. Light and dark tokens are unchanged.aria-liveis off#search-results, which re-announced the whole list on every keystroke. A visually hiddenrole="status"element now announces only the count ("8 results", "No results").shortcuts.tschecksdialog.openinstead ofhidden.src/scripts/search-modal.test.ts, which tests escaping, title-as-text, arrow and j/k navigation, and count labels.Verification
npm run check: 0 errorsnpx vitest run src/scripts/search-modal.test.ts: 13 passednpx eslinton changed TS files: cleanSKIP_PDF=1 npm run build: OKsearch-shortcuts,csp,accessibility-astroagainstastro preview: 71 passed🤖 Generated with Claude Code