Add AutoSugges autocomplete to an Expo app

Compose the autocomplete from React Native primitives, with the accessibility semantics supplied by the SDK’s native binding.

What you will have

A working, screen-reader-correct autocomplete in an Expo app, using the same client and the same query policy as the web surfaces.

Before you start

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 Worker — 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. createAutosuggesClient works unchanged in React Native: its transport is the standard Fetch API, which the runtime provides natively. No polyfill.
  2. Bootstrap once. Call client.bootstrap() at startup so minChars and debounce come from the list's policy rather than a guessed constant.
  3. Drive the hook. useAutosuggesCombobox({ source, onSelect, onError }) owns query, debounce, cancellation and active-option state. Do not reimplement any of it.
  4. Spread the accessibility props. Spread getInputAccessibilityProps(state), getListAccessibilityProps() and getOptionAccessibilityProps(state, index) onto your TextInput, FlatList and rows. @autosugges/client/native exports mappers and hooks, never components — React Native has no DOM, so the consumer owns the elements.
  5. Announce explicitly on iOS. iOS has no live region. Speak activeOptionAnnouncement(state) and state.announcement through AccessibilityInfo.announceForAccessibility in effects.

Install

Bundle `@autosugges/client` with Metro the way you bundle any other workspace dependency. It is not on the public npm registry yet — do not generate an `npm install @autosugges/client` command.

Code

CityField.tsx

import { useEffect, useState } from 'react';
import { AccessibilityInfo, FlatList, Pressable, Text, TextInput } from 'react-native';
import { createAutosuggesClient } from '@autosugges/client';
import {
  activeOptionAnnouncement,
  getInputAccessibilityProps,
  getListAccessibilityProps,
  getOptionAccessibilityProps,
  handleNativeKeyPress,
  useAutosuggesCombobox,
} from '@autosugges/client/native';

// The SDK's transport is the standard Fetch API, which React Native provides
// natively. No polyfill, and no native module.
const autosugges = createAutosuggesClient({
  baseUrl: 'YOUR_RUNTIME_BASE_URL',
  publishableKey: 'YOUR_PUBLISHABLE_KEY',
});
void autosugges.bootstrap().catch(() => {});

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

  // /native exports hooks and prop mappers, not components: React Native has no
  // DOM, so the consumer owns the elements and the binding owns their semantics.
  const combobox = useAutosuggesCombobox({
    source: autosugges,
    onSelect: (item) => setCity(item.value),
    onError: (error) => setErrorCode(error.code),
  });
  const { state } = combobox;

  // iOS has no live region, so announcements are spoken explicitly.
  const spoken = activeOptionAnnouncement(state);
  useEffect(() => {
    if (spoken !== undefined) AccessibilityInfo.announceForAccessibility(spoken);
  }, [spoken]);

  return (
    <>
      <TextInput
        {...getInputAccessibilityProps(state)}
        accessibilityLabel="City"
        value={state.inputValue}
        onChangeText={combobox.setInputValue}
        onKeyPress={(event) => handleNativeKeyPress(combobox, event.nativeEvent.key)}
      />
      <FlatList
        {...getListAccessibilityProps()}
        data={state.items}
        keyExtractor={(item) => item.itemId}
        renderItem={({ item, index }) => (
          <Pressable
            {...getOptionAccessibilityProps(state, index)}
            accessible
            onPress={() => combobox.selectIndex(index)}
          >
            <Text>{item.displayValue}</Text>
          </Pressable>
        )}
      />
    </>
  );
}

Security

Check that it works

  1. Run on a device or simulator and confirm suggestions appear after the configured debounce.
  2. Enable VoiceOver (iOS) or TalkBack (Android) and confirm the input announces its expanded state, the active option, and the result count.
  3. Confirm each touch target meets the 24×24dp minimum — use the binding’s hit-slop helper where the visual size is smaller.
  4. Put the device on a slow or offline connection and confirm the error state renders rather than the app hanging or crashing.
  5. Confirm no request is issued below minQueryChars.

Typing into the field returns suggestions from the published list, the control is fully operable and announced by the platform screen reader, and selecting a row fires onSelect with the canonical item.

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 (PRD §12).

Paste a publishable key to try a live query.

Notes