Skip to content

fix: focus the search input through the owning component instead of a DOM query - #3252

Open
Chirag6722 wants to merge 2 commits into
npmx-dev:mainfrom
Chirag6722:fix/3216-search-input-focus
Open

Chirag6722 wants to merge 2 commits into
npmx-dev:mainfrom
Chirag6722:fix/3216-search-input-focus

Conversation

@Chirag6722

Copy link
Copy Markdown

🔗 Linked issue

resolves #3216

🧭 Context

The / shortcut in app.vue and the ArrowUp-from-first-result handler in pages/search.vue both found the search input with document.querySelector('input[type="search"], input[name="q"]'). That selector depends on markup that lives in two other components (Header/SearchBox.vue and pages/index.vue), so a change to either input's attributes would silently break the shortcuts. Review on #3214 asked for the focus method to come from the component that owns the input instead.

📚 Description

Adds a small useSearchInputFocus composable with three parts:

  • provideSearchInputFocus() is called once in app.vue. It keeps a set of registered focus targets and exposes focus(), which tries them in order and returns true at the first one that focused something.
  • useSearchInputFocusTarget(fn) registers a target for the lifetime of the calling component scope (unregistered via onScopeDispose). Header/SearchBox.vue registers its existing focus() (which now returns false while the input is hidden by v-if, i.e. on the homepage), and pages/index.vue registers the homepage search input through a template ref.
  • useSearchInputFocus() returns the injected focus() for consumers; pages/search.vue uses it for ArrowUp.

app.vue's / handler becomes if (focusSearchInput()) return before falling back to router.push({ name: 'search' }), which is the same control flow as before with the DOM query removed.

Behaviour is intended to be unchanged: on the homepage the header box is not rendered, so the homepage input gets focus; elsewhere the header box does. One pre-existing edge is preserved rather than fixed: on mobile the header input exists but is hidden with CSS, so focus() is a no-op there, exactly as the old querySelector path was. Happy to follow up on that separately if wanted.

Tests:

  • test/nuxt/composables/use-search-input-focus.spec.ts covers focusing a registered target, the no-target/no-provider cases, first-success short-circuit, unregistration on unmount, and HeaderSearchBox registering itself and reporting false on the homepage. I checked that the last two fail when the registration line and the onScopeDispose cleanup are removed.
  • test/e2e/interactions.spec.ts gets one new case: on /, move focus off the autofocused input, press /, expect #home-search focused. That is the homepage registration path, which no existing e2e test exercised. The existing / and ArrowUp e2e tests on /search still pass against a TEST=1 build, and the new case fails when the useSearchInputFocusTarget call in pages/index.vue is removed.

vp lint, vp fmt --check, vp test --project nuxt for the new spec, and playwright test test/e2e/interactions.spec.ts -g "search|homepage" pass locally. I could not run test:types on this machine because the typescript-native-bridge binary is blocked by a local application-control policy, so please rely on CI for that.

AI help was taken for this change.

… DOM query

The '/' shortcut in app.vue and the ArrowUp handler on the search page
located the search input with a selector that depended on markup in
Header/SearchBox.vue and pages/index.vue. Add a useSearchInputFocus
composable: app.vue provides a registry, both search inputs register
their focus method, and the shortcut handlers call it.

resolves npmx-dev#3216
@agentscanapp

agentscanapp Bot commented Sep 14, 2026

Copy link
Copy Markdown

Thanks for opening this pull request! 🎉

We really appreciate you taking the time to contribute, @Chirag6722.

A maintainer will take a look as soon as they can. In the meantime, please make sure that:

  • the description explains what changed and why
  • any related issues are linked
  • existing tests still pass

If anything needs adjusting we'll leave comments here. Thanks again!

@vercel

vercel Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
npmx.dev Ready Ready Preview Sep 14, 2026 5:44am UTC
2 Skipped Deployments
Project Deployment Actions Updated
docs.npmx.dev Ignored Ignored Preview Sep 14, 2026 5:44am UTC
npmx-lunaria Ignored Ignored Sep 14, 2026 5:44am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: cf91d860-a96c-4860-97fe-f7b00008b8ab

📥 Commits

Reviewing files that changed from the base of the PR and between 0e3cdad and dfbc199.

📒 Files selected for processing (7)
  • app/app.vue
  • app/components/Header/SearchBox.vue
  • app/composables/useSearchInputFocus.ts
  • app/pages/index.vue
  • app/pages/search.vue
  • test/e2e/interactions.spec.ts
  • test/nuxt/composables/use-search-input-focus.spec.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Summary

Summary by CodeRabbit

  • New Features

    • Pressing / now reliably focuses the available search input, including on the homepage and search page.
    • Search focus works across different search interfaces and safely handles unavailable inputs.
  • Bug Fixes

    • Improved keyboard shortcut behaviour when search inputs are not currently rendered.
  • Tests

    • Added coverage for keyboard-triggered search focus and focus handling across common scenarios.

Walkthrough

The PR adds a scoped search-input focus context. The homepage and header register focus targets. Keyboard handlers use the context instead of DOM selectors. Unit and end-to-end tests cover focus routing, cleanup, route changes, and the / shortcut.

Changes

Search input focus

Layer / File(s) Summary
Focus context and target lifecycle
app/composables/useSearchInputFocus.ts
The new composables provide a scoped focus function, register focus targets, skip unavailable targets, and remove targets when their scope ends.
Application focus integration
app/pages/index.vue, app/components/Header/SearchBox.vue, app/app.vue, app/pages/search.vue
The homepage and header register focus targets. The / shortcut and search-page handler use the focus context. The / shortcut retains its search-route fallback.
Focus behaviour validation
test/nuxt/composables/use-search-input-focus.spec.ts, test/e2e/interactions.spec.ts
Tests cover focus results, target ordering, cleanup, missing providers, route changes, and homepage refocusing with /.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to dfbc1

Search focus routing preserves the navigation fallback when no target is available and includes lifecycle and shortcut coverage. The change is ready to merge.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: replacing the DOM query with focus handling owned by the search component.
Description check ✅ Passed The description is directly related to the changeset. It explains the composable, component registration, preserved behaviour, tests, and validation limits.
Linked Issues check ✅ Passed Issue #3216 requires removal of fragile selector queries from the app-level / shortcut and the search-page ArrowUp handler. app/app.vue now calls provideSearchInputFocus().focus, and `app/pages/…
Out of Scope Changes check ✅ Passed The changes remain within Issue #3216. The composable, input registrations, focus-method update, handler updates, and related unit and end-to-end tests all support component-owned search-input focus a…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codecov

codecov Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 55.55556% with 12 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/pages/index.vue 0.00% 5 Missing and 1 partial ⚠️
app/app.vue 0.00% 1 Missing and 1 partial ⚠️
app/composables/useSearchInputFocus.ts 84.61% 0 Missing and 2 partials ⚠️
app/components/Header/SearchBox.vue 80.00% 0 Missing and 1 partial ⚠️
app/pages/search.vue 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@graphieros graphieros left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Chirag6722
As you know, if you read our contribution guide, the use of AI to assist with coding is perfectly acceptable, as long as it is human driven.
However, using your own voice is required when communicating with npmx contributors.
Please consider writing the PR description with your own words. It can be in your native language if it is more practical.

Thank you^^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fragile SearchBox selector queries

2 participants