Integration Tiers

Three tiers, from drop-in to headless. Pick the one that matches how much DOM control you want.

Tier 1

Full component

Drop-in. Library creates input + dropdown + pills + keyboard + state.

Use when you want a complete widget with zero setup.

Tier 2

Dropdown only

Library renders dropdown + pills. You own the input element.

Use when you need a custom input (rich text, search bar, etc).

Tier 3

Headless

State + controllers + derived data. You render everything.

Use when you're building a framework wrapper or need full DOM control.

Tier 1 — full component

The library creates and owns the input, dropdown, pills, and all DOM. Just pass a container.

full.ts
import { AIAutocomplete } from "@magicx-eng/ai-autocomplete-vanilla";
const ac = new AIAutocomplete(container, {
renderMode: "full", // default
apiConfig: { apiKey: "pk_v1_your_public_key" },
placeholder: "Create a",
columns: 2,
mode: "auto", // "light" | "dark" | "auto"
pillPlacement: "inline", // "inline" | "dropdown" | "hidden"
onSubmit: (result) => console.log(result),
onError: (err) => console.error(err),
});
// Imperative methods
ac.focus();
ac.reset();
ac.setMode("dark");
ac.update({ animations: false, optionsPosition: "above" });
ac.destroy();

Tier 2 — dropdown only

You own the input element. The library renders the dropdown (with pills) inside a container you provide, and you wire your input's events into the library.

dropdown-only.ts
import { AIAutocomplete } from "@magicx-eng/ai-autocomplete-vanilla";
const input = document.getElementById("my-input") as HTMLTextAreaElement;
const dropdownContainer = document.getElementById("my-dropdown")!;
const ac = new AIAutocomplete(dropdownContainer, {
renderMode: "dropdown",
apiConfig: { apiKey: "pk_v1_your_public_key" },
onChange: (text) => {
if (input.value !== text) input.value = text;
},
});
const handleSubmit = () => {
sendToBackend(input.value);
ac.reset(); // start a new session
};
// Wire your input → library
input.addEventListener("input", () => ac.handleTextChange(input.value));
input.addEventListener("keydown", (e) => ac.handleKeyDown(e));
submitButton.addEventListener("click", handleSubmit);

Tier 3 — headless

No DOM at all. You get state, actions, and derived data. You render everything yourself. This is what framework wrappers (React, Vue, Svelte) use under the hood.

headless.ts
import { AIAutocomplete } from "@magicx-eng/ai-autocomplete-vanilla";
const ac = new AIAutocomplete(document.createElement("div"), {
renderMode: "headless",
apiConfig: { apiKey: "pk_v1_your_public_key" },
});
const handleSubmit = () => {
const state = ac.getState();
sendToBackend(state.text, state.completedParams);
ac.reset(); // start a new session
};
// Read state synchronously
const state = ac.getState();
// Subscribe to derived state
const unsubscribe = ac.subscribe((state) => {
renderMyInput(state.text, state.placeholderText);
renderMyPills(state.actionableSuggestions);
renderMyDropdown(
state.filteredOptions,
state.activeDropdownIndex,
state.isDropdownOpen,
);
});
// Forward user actions
myInput.addEventListener("input", () => ac.handleTextChange(myInput.value));
myInput.addEventListener("keydown", (e) => ac.handleKeyDown(e));
myOptionEl.addEventListener("click", () => ac.selectOption(option));
myPillEl.addEventListener("click", () => ac.setActivePill(index));
mySubmitButton.addEventListener("click", handleSubmit);
// Cleanup
unsubscribe();
ac.destroy();