DEV Community

Keep an Accessible Combobox Stable When Search Results Arrive Out of Order

The Problem

An accessible combobox can follow the correct ARIA pattern and still become unusable when two search responses arrive in the wrong order.

Reproducing the Race Condition

Reproduce this sequence:

  • Type ca, then quickly type cat.
  • The cat response arrives first and highlights cat facts.
  • The slower ca response arrives and replaces the list.
  • aria-activedescendant now points to an option that no longer exists.

IME Input Considerations

IME input adds another boundary: searching during composition can send partial text the user has not committed.

Modeling Request Generation

I would model the request generation explicitly:

let generation = 0;
let composing = false;

async function search(query: string) {
  const mine = ++generation;
  const options = await fetchOptions(query);
  if (mine !== generation || composing) return;
  render(options);
  restoreActiveOptionByKey();
}

The Stable Key Matters

An array index cannot preserve the active option when ranking changes.

Regression Matrix

Input Injected failure Expected evidence
ca โ†’ cat first request delayed only cat results render
Arrow Down result refresh active key survives or resets visibly
Escape response arrives afterward popup stays closed
IME composition network is fast no request until compositionend

Testing Recommendations

A Playwright test should assert:

  • Focus remains on the input.
  • Every aria-activedescendant resolves to a live element.
  • Escape invalidates outstanding generations.

A manual screen-reader pass should confirm result-count announcements are not emitted for discarded responses.

The WAI-ARIA Authoring Practices combobox pattern defines the keyboard contract. The missing production step is testing that contract under asynchronous replacement, not only against static example data.

Which stale-response failure has been hardest to reproduce in your search UI?

Top comments (0)

Comments

No comments yet. Start the discussion.