Three ways to integrate, from drop-in to fully headless — pick the one matching how much UI you want to own.
Tier 1
Full component
Drop-in <AIAutocomplete />. Owns the input, pills, dropdown, and state. Zero JSX you have to write.
Use when you want the complete widget with no setup.
Tier 2
Hook + dropdown
useAIAutocomplete() + <AIAutocompleteDropdown />. You own the input element; we render the dropdown and pills.
Use when you need a custom input but want our dropdown UI.
Tier 3
Headless
useAIAutocomplete() alone — state, actions, and derived data. You render the dropdown too.
Use when you need full control over every piece of the UI.
Tier 1 — drop-in component
The default. AIAutocomplete owns the input element, the dropdown, the pills, and the keyboard handling. Pass apiConfig + onSubmit and you're done.
import { AIAutocomplete } from "@magicx-eng/ai-autocomplete-react";export function App() {return (<AIAutocompleteapiConfig={{ apiKey: import.meta.env.VITE_MAGICX_PUBLIC_KEY }}onSubmit={(result) => console.log(result)}placeholder="Create a"/>);}
Controlled state
Pass value + completedParams + their setters to drive state externally. Useful inside form libraries or wizards. (This also works with the hook in Tier 2 and Tier 3.)
const [text, setText] = useState("");const [params, setParams] = useState([]);<AIAutocompletevalue={text}onChange={setText}completedParams={params}onParamsChange={setParams}onSubmit={(result) => console.log(result)}/>;
Imperative ref
Forward a ref to call focus(), reset(), or setMode() imperatively from the parent.
import { useRef } from "react";import {AIAutocomplete,type AIAutocompleteHandle,} from "@magicx-eng/ai-autocomplete-react";const ref = useRef<AIAutocompleteHandle>(null);// ref.current?.focus();// ref.current?.blur();// ref.current?.reset();// ref.current?.setMode("dark");<AIAutocomplete ref={ref} onSubmit={handleSubmit} />;
Tier 2 — hook + dropdown
Drive state with useAIAutocomplete() and render our <AIAutocompleteDropdown /> for the suggestions UI. You own the input element and the surrounding layout; we own the dropdown.
import {useAIAutocomplete,AIAutocompleteDropdown,} from "@magicx-eng/ai-autocomplete-react";export function HeadlessAutocomplete() {const { inputProps, dropdownProps, completedParams, reset } =useAIAutocomplete({apiConfig: { apiKey: import.meta.env.VITE_MAGICX_PUBLIC_KEY },});const handleSubmit = () => {sendToBackend(inputProps.value, completedParams);reset(); // start a new session};return (<div className="my-shell" style={{ position: "relative" }}><textarea {...inputProps} /><AIAutocompleteDropdown {...dropdownProps} mode="auto" /><button type="button" onClick={handleSubmit}>Submit</button></div>);}
Color mode
A standalone dropdown styles itself when you pass mode — "light", "dark", or "auto" (which follows the OS theme). It scopes the design tokens to its own root, so no .magicx-aia wrapper is needed. Leave mode unset only when the dropdown sits inside Tier 1 or your own .magicx-aia element, so it inherits that theme instead. (optionsPosition flows through dropdownProps too, so above/below placement works with no extra CSS.)
Custom & rich-text inputs
inputProps is shaped for a <textarea>. For a contentEditable or rich-text editor (Tiptap, ProseMirror, Lexical…) don't spread inputProps — call the actions directly: handleTextChange(text) on every edit, setFocused(bool) on focus/blur, handleKeyDown(event) for Arrow/Enter/Tab/Escape while the dropdown is open, and handleCaretMove(offset) so arrow keys can move into the dropdown.
Tier 3 — headless (bring your own UI)
Skip <AIAutocompleteDropdown /> and render the suggestions UI yourself. dropdownProps carries everything you need — the active suggestion's options, the highlighted index, and the onSelect / onHighlight actions — so you can build a fully custom dropdown while the hook keeps owning state, fetching, filtering, and keyboard logic.
import { useAIAutocomplete } from "@magicx-eng/ai-autocomplete-react";export function CustomDropdown() {const { inputProps, dropdownProps } = useAIAutocomplete({apiConfig: { apiKey: import.meta.env.VITE_MAGICX_PUBLIC_KEY },});// dropdownProps carries the data + actions — render it however you like.const { suggestions, activeIndex, isOpen, onSelect, onHighlight } =dropdownProps;const options = suggestions[0]?.options ?? [];return (<div style={{ position: "relative" }}><textarea {...inputProps} />{isOpen && (<ul className="my-dropdown" role="listbox">{options.map((option, i) => (<likey={option.text}role="option"aria-selected={i === activeIndex}onMouseEnter={() => onHighlight(i)}onMouseDown={(e) => {e.preventDefault(); // keep focus in the inputonSelect(option);}}>{option.text}</li>))}</ul>)}</div>);}