Skip to content
AutoSuggesAutoSugges home
Start free
Menu
Appearance
Appearance: System.

Add AutoSugges autocomplete to a React app

Mount the shipped accessible combobox in a React component — debounce, cancellation, keyboard navigation and ARIA are already wired.

How do I add autocomplete to a React app?

Create one client with createAutosuggesClient using your runtime base URL and publishable key, call bootstrap() once to read the list's query policy, then render the Autocomplete component from @autosugges/client/react with the client as its source. Debounce, request cancellation, keyboard navigation and ARIA roles are already wired.

What you will have

A working, accessible autocomplete input in a React application, querying a published AutoSugges list at the edge, with the list’s own query policy honoured and every failure rendered from the typed error code.

Before you start

  • An AutoSugges list that has been published at least once. An unpublished list has nothing to serve yet and returns list_not_published.
  • The publishable key issued for the application that will query it.
  • The runtime base URL for the environment you are targeting. AutoSugges does not have one fixed public hostname baked into the SDK — the dashboard's integration panel shows the origin for your environment.
  • React 18 or newer.

Values you supply

Each value this integration needs, where it comes from, and whether it is public
ValuePlaceholderWhere it comes from
baseUrlRequired · public by designYOUR_RUNTIME_BASE_URLThe AutoSugges dashboard's integration panel, for the environment you are deploying to. The origin of the AutoSugges runtime — scheme and host, no trailing slash and no path. The SDK appends /v1/... itself.
publishableKeyRequired · public by designYOUR_PUBLISHABLE_KEYThe AutoSugges dashboard, under the application that will make the queries. Identifies the consumer, the application, the subscription, the canonical list and the query policy in a single server-side lookup. The client never supplies a list id, tenant id or version hash — if a generated integration is passing one of those, it is wrong.
accessTokenOptional · never in client codeYOUR_SERVER_MINTED_ACCESS_TOKENYour own backend, which mints it from your AutoSugges credentials. Only for a list whose policy requires a token. Short-lived, sent as authorization: Bearer <token>, and never minted, stored or hardcoded in client code.

Steps

  1. Create one client. Call createAutosuggesClient({ baseUrl, publishableKey }) once, at module scope, so it is not recreated on every render.
  2. Bootstrap once. Call client.bootstrap() at startup. It resolves the list's real minQueryChars and debounceMs into client.policy; the component reads that live on every keystroke.
  3. Render the component. Import Autocomplete from the @autosugges/client/react subpath — not from the package root, which is deliberately React-free — and pass the client as source and a real accessible label.
  4. Handle the selection. onSelect receives (item, { ancestors }). Store item.value, render item.displayValue, and use ancestors to auto-fill parent fields without a second request.
  5. Handle the failures. onError receives an AutosuggesError. Switch on error.code against the vocabulary below; never render a hand-written message.

Install

npm install @autosugges/client

Code

city-field.tsx

import { useState } from 'react';
import { createAutosuggesClient } from '@autosugges/client';
import { Autocomplete } from '@autosugges/client/react';

// One client per app, created outside the component so it survives re-renders.
const autosugges = createAutosuggesClient({
  baseUrl: 'YOUR_RUNTIME_BASE_URL',
  publishableKey: 'YOUR_PUBLISHABLE_KEY',
});

// Reads the list's real minChars/debounce. Fire-and-forget: the
// component works on documented fallbacks until this resolves, and the SDK has
// already logged any failure once at its own boundary.
void autosugges.bootstrap().catch(() => {});

export function CityField() {
  const [city, setCity] = useState('');
  const [region, setRegion] = useState('');
  const [errorCode, setErrorCode] = useState<string | undefined>();

  return (
    <>
      <Autocomplete
        source={autosugges}
        label="City"
        placeholder="Start typing a city"
        onSelect={(item, { ancestors }) => {
          // item.value is what you store; item.displayValue is what was shown.
          // ancestors is the precomputed hierarchy chain, root first — use it to
          // auto-fill state/country fields without a second request.
          setCity(item.value);
          setRegion(ancestors.map((ancestor) => ancestor.displayValue).join(', '));
        }}
        onError={(error) => {
          // error is an AutosuggesError. Switch on error.code — the codes and
          // their remediation are listed below. Never invent a message string.
          setErrorCode(error.code);
        }}
      />
      <input type="hidden" name="city" value={city} />
      <input type="hidden" name="region" value={region} />
      {errorCode !== undefined && <p role="alert">Lookup unavailable ({errorCode}).</p>}
    </>
  );
}

Security

  • Both values in the snippet are public by design and belong in client code as written. If a generated integration adds a proxy route, an API secret or a server-side fetch "to protect the key", delete it — there is nothing to protect.

Check that it works

  1. Type fewer characters than the list’s minQueryChars and confirm no network request is made at all.
  2. Type a query at or above minQueryChars and confirm exactly one GET to /v1/query per settled input, not one per keystroke.
  3. Confirm the response items render displayValue, and that selecting one produces the value you expect in onSelect.
  4. Operate the whole control with the keyboard only: ArrowDown/ArrowUp move the active option, Enter selects, Escape closes.
  5. Temporarily set the publishable key to a wrong value and confirm the UI shows an error state driven by invalid_key rather than an empty list that looks like "no results".

Typing in the field produces a listbox of suggestions from the published list within the configured debounce, the field is fully keyboard-operable and announced by a screen reader, and selecting an option fires onSelect with the canonical item and its ancestors.

Try it live

Paste a publishable key from one of your published lists to run a real query against this environment’s runtime — the same @autosugges/client the code above uses.

A published list's publishable key — a public identifier, safe to paste here.

Paste a publishable key to try a live query.

Notes

  • Never hardcode a minimum query length or a debounce interval. Both come from client.policy, which the SDK fills from the bootstrap response and updates in place. The constants the SDK falls back to before the first successful bootstrap are documented defaults, not the list’s real policy.
  • Render displayValue, store value. They differ: displayValue is resolved for the requested locale at compile time.
  • A selection report is optional. Omitting it costs ranking quality over time and nothing else; it is never required for a query to work.
  • The component renders its own ARIA combobox pattern. Do not add role="combobox" or aria-* attributes around it — you will produce a nested, conflicting pattern.

Recipes for specific datasets

The same integration, specialised to the datasets whose behaviour changes the code.

Frequently asked questions

What is the minimum number of characters before a query runs?
Two by default. A list owner can change the minimum, but it can never be 1. The client reads the real value from bootstrap and sends no request below it, so do not hardcode it.
How long does the client wait after typing before it queries?
150 milliseconds by default. The value is delivered through bootstrap and a list owner can raise it, so the client uses the policy value rather than a constant.
How many suggestions does a query return?
Ten by default, unless the list owner sets a different default result limit.
Where does the publishable key go?
In the key query parameter of the request, for example /v1/query?key=YOUR_PUBLISHABLE_KEY, never in a header. The key is public by design and safe in client code. Secret keys never belong in a browser or mobile bundle, and a proxy to hide the publishable key is unnecessary.
What happens when my query quota runs out?
The runtime returns a structured quota_exceeded response that carries no items and no placeholder suggestions, so exhaustion is never mistaken for no results. Render it from the typed error code and prompt an upgrade.
Does AutoSugges work in React Native?
Yes. The same client runs in React Native because its transport is the standard Fetch API, and @autosugges/client/native provides hooks and accessibility prop mappers for Expo and bare React Native apps. See the Expo guide.