Skip to content

docs(search): force Algolia DocSearch modal to autofocus its input on Cmd+K#202

Draft
mateo-berri wants to merge 1 commit into
mainfrom
litellm_search-cmdk-autofocus-b8dd
Draft

docs(search): force Algolia DocSearch modal to autofocus its input on Cmd+K#202
mateo-berri wants to merge 1 commit into
mainfrom
litellm_search-cmdk-autofocus-b8dd

Conversation

@mateo-berri
Copy link
Copy Markdown
Collaborator

Why

Per Mik's report on the eng channel after the Algolia migration: when a user hits Cmd+K on the docs site, the search modal opens but the cursor doesn't appear in the search box — the user has to click the input before they can start typing. The behavior is intermittent: sometimes the caret is in the right place, sometimes it isn't.

Root cause

@docusaurus/theme-search-algolia renders the DocSearch modal like this:

const openModal = useCallback(() => {
  prepareSearchContainer();
  importDocSearchModalIfNeeded().then(() => setIsOpen(true));
}, [prepareSearchContainer]);

Two things make autofocus racy:

  1. The modal component is loaded via a dynamic import() on first invocation, so the modal mounts asynchronously after the keydown event.
  2. The modal is rendered into a portal that is prepended to document.body (document.body.insertBefore(divElement, document.body.firstChild)).

The modal input has React's autoFocus, which schedules a .focus() call after mount. That call sometimes loses the race against:

  • the previously focused element re-asserting focus when the portal is inserted before it, and
  • third-party scripts reacting to body mutations (e.g. the Crisp chat widget we load via the cripchat plugin).

Result: the modal renders but the input is never focused, until the user clicks it.

Fix

Add a small client module (src/clientModules/algoliaSearchAutofocus.js) that runs on every page and:

  • Starts a MutationObserver on document.body for the lifetime of the page.
  • When a .DocSearch-Container element is inserted, schedules three idempotent focus attempts on its .DocSearch-Input — synchronous, next animation frame, and 60 ms later — so the input ends up focused even if something else stole focus during the React commit phase.
  • Places the caret at the end of any pre-filled query so typing appends instead of replaces.

Each attempt is a no-op if the input is already focused, so this never fights React's own autoFocus when it wins the race on the first try.

Wired up via the top-level clientModules array in docusaurus.config.js (see Docusaurus client modules docs).

Verification

  • npm run build succeeds (broken-anchor warnings on release_notes/* are pre-existing).
  • The compiled main JS bundle contains both MutationObserver and the .DocSearch-Container / .DocSearch-Input selectors, confirming the module is wired up and ships to clients.
  • The hook is purely additive — if Algolia's own autoFocus already worked, our .focus() calls are no-ops, so there is no risk of regressing the case where focus is already correct.

Slack Thread

Open in Web Open in Cursor 

… Cmd+K

The Algolia DocSearch modal is loaded via a dynamic import and rendered
into a portal that is prepended to document.body. The input is marked
with React's autoFocus, but in practice the call sometimes loses the
race against:
  - the modal portal being inserted before the previously active
    element (which can immediately re-assert focus), and
  - third-party scripts on the page reacting to body mutations
    (e.g. the Crisp chat widget loaded via the cripchat plugin).

Result: the modal opens but the caret never lands in the search input,
and the user has to click the input before they can type. The bug is
intermittent — sometimes autoFocus wins the race, sometimes it loses.

Add a client module that runs a MutationObserver on document.body for
the lifetime of the page. Whenever a .DocSearch-Container element is
inserted, schedule three idempotent focus attempts on its
.DocSearch-Input (synchronous, next animation frame, and 60ms later)
and place the caret at the end of any pre-filled query.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 22, 2026

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

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment May 22, 2026 4:30pm

Request Review

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.

2 participants