SearchJetEngine
React Autocomplete Search Component

Search-as-You-Type Autocomplete for React

A debounced, keyboard-navigable, accessible autocomplete dropdown backed by a hosted search API. Debounce, highlighting, and a11y included — you bring the styling.

Debounced by default
Typo-tolerant matching
Full a11y + keyboard support

See It Working — Type Right Here

Try “wireless headphons” (typo included). Keyboard arrows work too.

Building Autocomplete from Scratch is a Trap

Debouncing, request races, keyboard navigation, accessibility, empty states — that's a week of work before you even test. SearchJet handles it all.

Naive onChange = API Spam

Firing a fetch on every keystroke hammers your API and renders stale results. A production autocomplete needs debouncing, request cancellation, and race-condition guards.

Keyboard Navigation is Hard

Arrow-up / arrow-down to move through suggestions, Enter to select, Escape to dismiss — building accessible combobox behavior from scratch is notoriously fiddly and a common a11y failure.

Empty Results, Empty UX

Without a server-side "no match" strategy, your users hit dead ends. A great autocomplete also suggests popular queries when there are no exact hits.

Copy-Paste Implementation

Two Ways to Build It

Drop-in component, or a headless hook if you want full control.

Drop-in <Autocomplete />

App.jsx
import { SearchProvider, Autocomplete } from '@searchjet/react';

function App() {
  return (
    <SearchProvider
      indexName="docs"
      searchApiKey="your_search_api_key"
    >
      {/* Search-as-you-type: debounced, keyboard + a11y ready */}
      <Autocomplete
        placeholder="Search docs, products…"
        maxSuggestions={6}
        debounceMs={150}
        onSelect={(hit) => {
          window.location.href = hit.url ?? `/product/${hit.id}`;
        }}
      />
    </SearchProvider>
  );
}

Headless hook (debounce + races handled)

useSearchJet.js
import { useState, useEffect, useCallback } from 'react';

/** Headless autocomplete — full control, zero assumptions */
function useSearchJet(value) {
  const [suggestions, setSuggestions] = useState([]);
  const [status, setStatus] = useState('idle');

  useEffect(() => {
    let cancelled = false;               // race-condition guard
    if (!value.trim()) {
      setSuggestions([]);
      setStatus('idle');
      return;
    }

    const timer = setTimeout(async () => {
      setStatus('loading');
      const res = await fetch(`/api/search?q=${encodeURIComponent(value)}`);
      const data = await res.json();
      if (!cancelled) {
        setSuggestions(data.results);
        setStatus('success');
      }
    }, 200);                             // debounce

    return () => {
      cancelled = true;                  // drop stale responses
      clearTimeout(timer);
    };
  }, [value]);

  return { suggestions, status };
}

export function AutocompleteHeadless() {
  const [query, setQuery] = useState('');
  const [active, setActive] = useState(-1);
  const { suggestions } = useSearchJet(query);

  const onKeyDown = (e) => {
    if (e.key === 'ArrowDown') setActive((a) => (a + 1) % suggestions.length);
    if (e.key === 'ArrowUp') setActive((a) => (a <= 0 ? suggestions.length - 1 : a - 1));
    if (e.key === 'Enter' && active > -1) {
      const hit = suggestions[active];
      window.location.href = hit.url;
    }
  };

  return (
    <input
      onChange={(e) => { setQuery(e.target.value); setActive(-1); }}
      onKeyDown={onKeyDown}
      role="combobox"
      aria-expanded={suggestions.length > 0}
      placeholder="Type to search…"
    />
  );
}

From Zero to Autocomplete in 4 Steps

1

Get your free API key

Generate a key on the JavaScript SDK page — the widget injects it straight into your clipboard-ready code.

2

Install @searchjet/react

One npm install. The package ships typed Autocomplete, SearchBox, RefinementList, and Hits components.

3

Drop in <Autocomplete />

Debounced by default. Set maxSuggestions, placeholder, and an onSelect handler for routing.

4

Ship it

Styling via CSS variables, dark mode support, full keyboard + screen-reader support included. Done in minutes.

Frequently Asked Questions

How do I debounce search input in React?
The SDK's Autocomplete debounces input for you (debounceMs prop). For a headless approach, wrap your search call in a custom hook that clears a timeout on each keystroke — the headless example below shows the full pattern.
Does the autocomplete support keyboard navigation?
Yes. Arrow keys move the active suggestion, Enter selects, Escape closes the dropdown, and the component exposes the correct combobox ARIA roles for screen readers.
Can I highlight matched text in the suggestions?
Yes — the SDK returns _formatted fields with <em> highlight tags. The demo on this page highlights matches automatically using the same mechanism.
Can I use autocomplete without a React library?
Absolutely. The headless SearchJet client works with vanilla JS, Vue, Svelte, or any framework — see the Vanilla JS site search guide for a framework-free version.
Is the search API fast enough for search-as-you-type?
SearchJet sub-2ms edge-cached lookups are designed for search-as-you-type. Queries are typo-tolerant, so "wireles headphons" still returns wireless headphones.

Ship a Production-Ready Autocomplete Today

Free forever plan. 10,000 searches/month. No credit card.

More Search Recipes