Add AutoSugges autocomplete to a plain HTML page

Mount an accessible autocomplete on an ordinary HTML page from a data attribute, with no framework and no hand-written combobox markup.

What you will have

A working autocomplete on a plain HTML page, rendered inside a shadow root so it cannot collide with the host page’s styles, with no combobox markup written by hand.

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. Mark up one element. Give any element data-autosugges-key and data-autosugges-base-url. Optional: data-autosugges-label, -placeholder, -locale, -theme.
  2. Import the browser binding. Import @autosugges/client/browser in a <script type="module">. The import itself triggers a one-time scan that mounts every [data-autosugges-key] element.
  3. Or mount explicitly. For markup injected after that scan, or when you need the selection event, call mountAutocomplete(target, { source, label, onSelect, onError }) with a client you created yourself.
  4. Style it from outside. The widget lives in a shadow root. Theme it with the documented CSS custom properties from an ancestor; host page rules cannot reach inside it, and its rules cannot leak out.

Install

Bundle `@autosugges/client` with your existing build tool. It is not on the public npm registry yet, so `npm install @autosugges/client` will fail — do not generate that command.

Code

index.html

<!-- Option A — no JavaScript to write. The browser binding scans for this
     attribute on import and mounts an accessible combobox (input + listbox +
     live region) inside its own shadow root, so page styles cannot leak in. -->
<div
  data-autosugges-key="YOUR_PUBLISHABLE_KEY"
  data-autosugges-base-url="YOUR_RUNTIME_BASE_URL"
  data-autosugges-label="City"
  data-autosugges-placeholder="Search for a city"
></div>

<script type="module">
  // Bundle @autosugges/client with your build tool and import the /browser
  // entry. Importing it is what triggers the one-time scan.
  import '@autosugges/client/browser';
</script>

<!-- Option B — explicit control, for markup injected after that scan ran, or
     when you need the selection event. -->
<div id="city-mount"></div>
<p id="city-error" role="alert"></p>

<script type="module">
  import { createAutosuggesClient } from '@autosugges/client';
  import { mountAutocomplete } from '@autosugges/client/browser';

  const source = createAutosuggesClient({
    baseUrl: 'YOUR_RUNTIME_BASE_URL',
    publishableKey: 'YOUR_PUBLISHABLE_KEY',
  });
  void source.bootstrap().catch(() => {});

  const mounted = mountAutocomplete(document.getElementById('city-mount'), {
    source,
    label: 'City',
    onSelect(item, { ancestors }) {
      // Wire item.value / item.displayValue / ancestors into your form.
    },
    onError(error) {
      // Never invent a message: error.message is already the SDK's safe,
      // ErrorCode-mapped text. Show it, or branch on error.code.
      document.getElementById('city-error').textContent = error.message;
    },
  });
  // mounted.destroy() removes every node and listener it added.
</script>

Security

Check that it works

  1. Load the page and confirm an input appears inside the target element and that the element gained a data-autosugges-mounted attribute.
  2. Type below and then above the minimum query length and confirm requests start only at the threshold.
  3. Confirm the widget is keyboard-operable and that a screen reader announces the result count.
  4. Remove data-autosugges-base-url and confirm the element renders a safe inline message instead of throwing into the page.
  5. If you mounted explicitly, call mounted.destroy() and confirm every node and listener is removed.

An accessible input and listbox appear where the target element was, isolated in a shadow root, returning suggestions from the published list.

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