Every input, output, observable, and method — distilled.
<ai-autocomplete>
The full drop-in standalone component. Owns the contentEditable editor, inline pills, dropdown, and all state. Implements ControlValueAccessor for Reactive Forms.
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
apiConfig | APIConfig | — | Runtime API configuration (public key or access token). |
additionalContext | Record<string, unknown> | — | Optional user context. Include whatever you know about the user (a profile, preferences, workspace, anything) to personalize suggested parameters and options to them. |
pillPlacement | "inline" | "dropdown" | "hidden" | "dropdown" | Where unfilled pills render. inline lives in the input; dropdown places them with the options; hidden shows none. |
mode | "light" | "dark" | "auto" | "auto" | Color mode. auto follows prefers-color-scheme. |
optionsPosition | "above" | "below" | "below" | Where the dropdown opens relative to the input. |
animations | boolean | true | Enable the selection streak + new-param shimmer. |
dropdownTrigger | "auto" | "manual" | "hidden" | "auto" | When the dropdown appears. auto = when options are available; manual = only on pill tap; hidden = never. |
closeDropdownOnBlur | boolean | true | When false, the dropdown stays open even when the editor loses focus. |
showNonTappableOptions | boolean | true | Render non-tappable options alongside tappable ones. |
columns | number | 2 | Number of columns in the dropdown grid. |
maskCompletedText | boolean | false | Strip completed-param text from network requests (PII masking). |
optionOverrides | OptionOverrides | — | Inject or compute option lists per suggestion type. |
autoFocus | boolean | true | Focus the editor on mount. Set false to leave focus to the consumer. |
value | string | — | Controlled text value. Pair with (valueChange). |
completedParams | CompletedParamState[] | — | Controlled completed params. Pair with (completedParamsChange). |
submitButton | TemplateRef | null | — | A <ng-template> to replace the default arrow button. Pass null to render no button. |
showProducts | boolean | true | Render the product strip below the options whenever there are products to show: by default the items the /suggest response reports as matching the query, or the results of a custom products search. Set to false to render no strip and run no custom search. |
products | ProductsConfig | — | Custom source for the product strip. Omit it and the strip shows the items the /suggest response itself reports as matching the query, with no extra request. Set it and the strip is fed by your own search endpoint on the SDK's existing fetch cadence instead; the server's items are then not rendered. Takes { fetch, transform }: fetch runs your search and must honour the AbortSignal it's handed, transform maps the raw payload to Product[]. Bind a stable reference (a component field, not an inline object literal). |
productsLayout | "row" | "list" | "row" | How the product strip lays its cards out. "row" is a horizontally scrolling shelf. "list" stacks the same cards as full-width rows (thumbnail on the left, title, vendor and price on the right) for results that read as a list, such as courses, listings or documents, rather than products on a shelf. The list scrolls vertically inside --aia-product-list-max-height, 320px by default. Changing the binding re-lays the strip out at once, and <ai-autocomplete-dropdown> takes the same input in Tier 2. |
Outputs
| Prop | Type | Description |
|---|---|---|
submitted | EventEmitter<AutocompleteResult> | Emits on Enter or submit-button click. Carries an AutocompleteResult. |
errored | EventEmitter<Error> | Emits when a fetch fails. |
valueChange | EventEmitter<string> | Emits when text changes (controlled mode). |
completedParamsChange | EventEmitter<CompletedParamState[]> | Emits when completed params change (controlled mode). |
focused | EventEmitter<void> | Emits when the editor gains focus. |
blurred | EventEmitter<void> | Emits when the editor loses focus. |
productSelect | EventEmitter<Product> | Emits when the user activates a product card. The SDK never navigates — you decide what a selection means. Modifier and middle clicks are left to the browser and don't emit. |
Imperative methods
Call these on the component instance via a template reference variable + @ViewChild.
| Prop | Type | Description |
|---|---|---|
focus() | () => void | Focus the editor. |
blur() | () => void | Blur the editor. |
reset() | () => void | Clear all state, rotate the session, and re-fetch. |
setMode() | (mode: AppearanceMode) => void | Switch color mode at runtime. |
AIAutocompleteController
A plain TypeScript class — no DI. Create it with new in ngOnInit, hold the reference, and call destroy() in ngOnDestroy. Exposes the SDK's reactive state as RxJS observables plus action methods.
Constructor options
Pass these to the constructor. Event callbacks (onSubmit, onError, …) are registered once at construction — for dynamic reactivity, subscribe to the observables instead.
| Prop | Type | Default | Description |
|---|---|---|---|
apiConfig | APIConfig | — | Runtime API configuration (key or token). |
additionalContext | Record<string, unknown> | — | Optional user context. Include whatever you know about the user (a profile, preferences, workspace, anything) to personalize suggested parameters and options to them. |
optionsPosition | "above" | "below" | "below" | Where the dropdown opens. Read by the keyboard controller to pick the open key. |
dropdownTrigger | "auto" | "manual" | "hidden" | "auto" | When the dropdown appears. |
closeDropdownOnBlur | boolean | true | When false, the dropdown stays open even when the input loses focus. |
showNonTappableOptions | boolean | true | Render non-tappable options alongside tappable ones. |
columns | number | 2 | Number of columns in the dropdown grid. |
maskCompletedText | boolean | false | Strip completed-param text from network requests (PII masking). |
optionOverrides | OptionOverrides | — | Override option lists per suggestion type. |
value | string | — | Initial controlled text value. |
completedParams | CompletedParamState[] | — | Initial controlled completed params. |
onSubmit / onError / onChange | (...) => void | — | onSubmit, onError, onChange, onParamsChange, onFocus, onBlur — registered once at construction. |
showProducts | boolean | true | Same as the Tier 1 input: false renders no strip and runs no custom search. |
products | ProductsConfig | — | Custom source for the product strip, same shape as the Tier 1 input. Omit it and products$ carries the items the /suggest response reports; set it and products$ carries your search's results instead. |
onProductSelect | (product: Product) => void | — | Called when the user activates a product card. Registered once at construction, like the other callbacks. The SDK never navigates. |
Observables
Each field is exposed as a stand-alone observable plus a composite state$. All run through distinctUntilChanged + shareReplay, so multiple async pipes share one subscription.
| Prop | Type | Description |
|---|---|---|
state$ | Observable<AIAutocompleteControllerState> | Snapshot of every public field in one object — convenient for *ngIf="ctrl.state$ | async as state". |
dropdown$ | Observable<AIAutocompleteDropdownState> | Composite stream for the dropdown view (suggestions, activeIndex, isOpen, pills, …) — bound to <ai-autocomplete-dropdown> via [controller], or subscribe to it directly to render your own dropdown in Tier 3. |
text$ | Observable<string> | Current editor text. |
completedParams$ | Observable<CompletedParamState[]> | Filled parameters. |
suggestionPills$ | Observable<Suggestion[]> | Actionable suggestion pills. The first item is the active pill. |
segments$ | Observable<Segment[]> | Input text split into typed text vs completed-param segments. |
isLoading$ | Observable<boolean> | Whether a fetch is in progress (UI-visible). |
isDropdownOpen$ | Observable<boolean> | Whether the dropdown should be visible. |
isReady$ | Observable<boolean> | Server indicates the query is complete. |
error$ | Observable<Error | null> | Last fetch error, or null. |
activeIndex$ | Observable<number> | Highlighted dropdown option index. -1 = none. |
suggestions$ | Observable<Suggestion[]> | Every suggestion from the last response, including the placeholder-type one. suggestionPills$ is this list minus the placeholder. |
skippedParams$ | Observable<SkippedParamState[]> | Suggestions the user dismissed with the skip key (→). Nothing renders them; they're folded into the wire completed_params array on every request and submit result. |
placeholderText$ | Observable<string> | Resolved placeholder text for the current step. |
newParamId$ | Observable<string | null> | ID of the most recently added param, for driving the shimmer animation. Clear it with clearNewParamId(). |
isFocused$ | Observable<boolean> | Whether the editor currently has focus, as last reported through the input binder or setFocused(). |
isActivePillSelected$ | Observable<boolean> | Whether the leading pill should render selected (full opacity) rather than de-emphasized — true while a tappable option is highlighted. |
products$ | Observable<Product[]> | What the product strip shows: the items the latest response reported as matching the query, or the results of a custom products search. Always empty while showProducts is false. |
customFields$ | Observable<CustomFieldsReport | null> | The catalog report the latest response carried, or null when it carried none. See CustomFieldsReport below. |
Actions
Thin pass-throughs to the headless core. After destroy() they no-op safely.
| Prop | Type | Description |
|---|---|---|
handleTextChange() | (value: string) => void | Call when the user types. Handles capitalization, param reconciliation, and filtering. |
handleKeyDown() | (e: KeyboardEvent) => void | Forward keyboard events from your input. Handles arrow nav, Enter, Tab, Escape. |
setFocused() | (focused: boolean) => void | Notify the controller the input gained or lost focus. Custom inputs only — [aiaInput] does this for you. |
handleCaretMove() | (offset: number | null) => void | Report the caret position (plain-text offset) so arrow keys can move into the dropdown. Custom inputs only. |
selectOption() | (option: SuggestionOption) => void | Select a dropdown option — updates text, creates a completed param, triggers shimmer. |
selectProduct() | (product: Product) => void | Announce a product-card activation, emitting productSelect / calling onProductSelect. The built-in dropdown calls this for you; call it yourself only when rendering your own strip from products$. |
setActiveDropdownIndex() | (index: number) => void | Highlight a dropdown option by index (-1 = none). Use it to wire hover/keyboard highlighting when rendering your own dropdown. |
setActivePill() | (index: number) => void | Move the pill at index to the front (active). |
removeLastParam() | () => void | Remove the last completed param and restore it as a pill. |
setValue() | (text: string) => void | Set the editor text (controlled mode). |
setCompletedParams() | (params: CompletedParamState[]) => void | Set completed params (controlled mode). |
reset() | () => void | Clear all state, rotate the session, and re-fetch. Call after submit. |
update() | (opts: AIAutocompleteControllerUpdate) => void | Apply runtime option changes (e.g. dropdownTrigger, optionsPosition). Event callbacks can't be swapped — subscribe to the observables instead. |
getState() | () => AIAutocompleteControllerState | Synchronous snapshot of the current state (for use inside event handlers). |
destroy() | () => void | Release subscriptions and the underlying core. Call in ngOnDestroy. |
<ai-autocomplete-dropdown>
Tier 2 dropdown component. Pass it the same controller — it renders the pillbar, options grid, and loading skeleton, and forwards actions back to the controller.
| Prop | Type | Default | Description |
|---|---|---|---|
controllerRequired | AIAutocompleteController | — | The controller that owns the autocomplete state. |
showPills | boolean | true | Whether to render the pillbar inside the dropdown. |
productsLayout | "row" | "list" | "row" | How the product strip lays its cards out. Same values and default as the <ai-autocomplete> input. |
mode | "light" | "dark" | "auto" | — | Color mode for a standalone dropdown — self-scopes the SDK tokens so no .magicx-aia wrapper is needed. "auto" follows prefers-color-scheme. Leave unset when nested inside a .magicx-aia ancestor (e.g. Tier 1). |
className | string | — | CSS class applied to the dropdown root. |
[aiaInput] directive
Attach [aiaInput]="controller" to your own <textarea> or <input> to wire its events (input, keydown, focus, blur, caret moves) into the controller and mirror state into ARIA attributes. Implements ControlValueAccessor, so it also works with [formControl] / [(ngModel)].
AutocompleteResult
The shape emitted by (submitted).
| Prop | Type | Description |
|---|---|---|
query | string | Plain text as the user sees it. |
raw_query | string | Text with placeholder tokens (e.g. "Create a {{TASK_1}}"). |
completed_params | CompletedParam[] | Filled parameter values. |
custom_fields | CustomFieldsReport | The catalog report for this response, when it carried one. Omitted, not null, when no catalog was read. See CustomFieldsReport below. |
CustomFieldsReport
The catalog report. Every response that read your product catalog also says what it did with the query. The controller exposes it as customFields$ (and on state$), and it rides on AutocompleteResult as custom_fields.
| Prop | Type | Description |
|---|---|---|
applied_filters | ExpressedFilter[] | Constraints the server read out of the query and the catalog answered, each { param, value, op } with op one of eq, ne, lt, lte, gt, gte. Always an array. |
dropped_filters | ExpressedFilter[] | Constraints the query expressed that the catalog could not answer: a parameter it does not have, a bound that is not a number, or a value no item carries. The items were narrowed without them, so this list is what tells "87 black t-shirts" from "no black item, so here are t-shirts". Always an array. |
items.total | number | How many items the applied filters left standing. Also counts what the query's own words matched, so it drops as a typed word starts matching a title. |
items.matched | MatchedItem[] | The items themselves, capped by the server. This is the list the product strip renders. Empty with a non-zero total when nothing narrowed the catalog, since naming arbitrary items as matches would mislead. |
null (no custom_fields key on the result) means the response carried no report: no catalog was read for it, such as a product with no catalog, the starting state, or a response with no option-bearing parameter to offer. That is "no news", not an empty catalog. The strip clears on such a response rather than keeping an older query's items, and the report stays readable while showProducts is false.