Skip to content

fix(nav): focus search input when mobile menu opens#523

Merged
gkorland merged 2 commits into
mainfrom
fix/mobile-search-autofocus
Jul 8, 2026
Merged

fix(nav): focus search input when mobile menu opens#523
gkorland merged 2 commits into
mainfrom
fix/mobile-search-autofocus

Conversation

@gkorland

@gkorland gkorland commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #518 (already merged). Code review flagged a focus-order inconsistency introduced by that fix: the search box now appears visually at the top of the mobile menu, but keyboard/screen-reader Tab order is unchanged (nav links first, search last), since only CSS position moved, not DOM order.

Changes

  • Focus #search-input automatically when the mobile menu is opened, so keyboard focus lands where the search box now visually appears.
  • The listener is attached in head_custom.html, which loads after just-the-docs.js, so by the time it runs the theme's own click handler has already toggled nav-open — no timing hacks (e.g. setTimeout) needed.
  • Confirmed this does not prematurely trigger the expanded search-results UI (.search-active is gated on non-empty input, unaffected by focus alone) and has no effect on desktop, where the menu button is hidden (display: none at >= 50rem).

Testing

Verified with headless Chromium (Playwright), injecting the change at its real position in <head> to preserve script execution/registration order:

  • Opening the mobile menu moves focus to #search-input.
  • Closing and reopening the menu re-focuses correctly each time.
  • Typing after auto-focus still triggers search results normally (existing behavior unaffected).
  • Escape still clears the input as before.
  • Desktop (menu button hidden) is unaffected; programmatic click doesn't throw.

Memory / Performance Impact

N/A — small JS listener, no measurable perf impact.

Related Issues

Follow-up to #518.

Summary by CodeRabbit

  • Bug Fixes
    • Improved mobile menu accessibility by automatically moving focus to the search field when the menu opens.
    • Better aligns keyboard and screen-reader focus with the visible order of items in the expanded mobile navigation.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@gkorland, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 613f85c0-78da-4dde-8fd0-886ce3dc4c53

📥 Commits

Reviewing files that changed from the base of the PR and between 83ee56b and c091742.

📒 Files selected for processing (1)
  • _includes/head_custom.html
📝 Walkthrough

Walkthrough

Added a client-side script in _includes/head_custom.html that listens for clicks on the mobile menu button and moves keyboard focus to the search input when the header's navigation menu is opened.

Changes

Mobile Menu Focus Script

Layer / File(s) Summary
Focus management on menu open
_includes/head_custom.html
Adds a DOMContentLoaded listener that, on menu button click, focuses the search input if the header has the nav-open class.

Estimated code review effort: 1 (Trivial) | ~3 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: focusing the search input when the mobile menu opens.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mobile-search-autofocus

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
_includes/head_custom.html (1)

64-67: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider deferring the nav-open check for robustness against handler ordering.

The click handler checks mainHeader.classList.contains("nav-open") synchronously, relying on just-the-docs' own click handler having already toggled the class. This works today because just-the-docs registers its handler before this one, but the ordering is implicit and fragile — a future just-the-docs update that wraps its handler registration in DOMContentLoaded (or changes include order) would silently reverse the execution order. In that scenario, the check would see stale state: on open, nav-open wouldn't be present yet (focus wouldn't move), and on close, nav-open would still be present (focus would incorrectly move during close).

Wrapping the check in setTimeout(fn, 0) defers it until after all synchronous click handlers have run, making the behavior independent of registration order.

♻️ Proposed refactor: defer the nav-open check
   menuButton.addEventListener("click", function () {
-    if (mainHeader.classList.contains("nav-open")) {
-      searchInput.focus();
-    }
+    setTimeout(function () {
+      if (mainHeader.classList.contains("nav-open")) {
+        searchInput.focus();
+      }
+    }, 0);
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@_includes/head_custom.html` around lines 64 - 67, The menuButton click
handler currently checks mainHeader.classList.contains("nav-open")
synchronously, which depends on just-the-docs’ handler running first and is
fragile. Update the click handler in the menuButton listener to defer the
nav-open state check until after synchronous click handlers finish (for example
by moving the focus logic into a zero-delay timeout), so the behavior in
head_custom.html no longer depends on handler registration order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@_includes/head_custom.html`:
- Around line 59-61: The selector lookup in the head custom script is using IDs
that do not exist, causing the setup to abort before the focus behavior runs.
Update the DOM queries in the script around menuButton/mainHeader/searchInput to
use the theme’s real selectors from the markup and styles, specifically the
class-based header/nav elements instead of `#main-header` and `#search-input` while
keeping `#menu-button` for the toggle button. Make sure the variables used by the
focus handoff logic still resolve to the actual header, nav, and search elements
so the guard no longer exits early.

---

Nitpick comments:
In `@_includes/head_custom.html`:
- Around line 64-67: The menuButton click handler currently checks
mainHeader.classList.contains("nav-open") synchronously, which depends on
just-the-docs’ handler running first and is fragile. Update the click handler in
the menuButton listener to defer the nav-open state check until after
synchronous click handlers finish (for example by moving the focus logic into a
zero-delay timeout), so the behavior in head_custom.html no longer depends on
handler registration order.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9cc6c129-e878-4e73-a826-e988b2856c05

📥 Commits

Reviewing files that changed from the base of the PR and between bc29699 and 83ee56b.

📒 Files selected for processing (1)
  • _includes/head_custom.html

Comment thread _includes/head_custom.html
Code review of #518 found that moving the search box to the top of the
mobile menu (visually) left keyboard/screen-reader focus order
unchanged: Tab still traverses the whole nav list before reaching
search, since DOM order wasn't touched, only CSS position. That's now
inconsistent with the new visual order.

Focus the search input as soon as the mobile menu opens, matching its
new position at the top. The listener runs after Just the Docs' own
(head_custom.html loads after just-the-docs.js), so nav-open has
already been toggled by the time it checks. Confirmed this doesn't
prematurely expand the search results UI (that's gated on non-empty
input, unaffected by focus alone) and doesn't affect desktop, where
the menu button is hidden.

Verified via headless Chromium: menu open -> focus lands on
#search-input; typing still triggers results normally; desktop
unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gkorland gkorland force-pushed the fix/mobile-search-autofocus branch from 83ee56b to 0660fbe Compare July 8, 2026 11:21
@gkorland gkorland merged commit e1352de into main Jul 8, 2026
4 checks passed
@gkorland gkorland deleted the fix/mobile-search-autofocus branch July 8, 2026 11:46
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.

1 participant