Autocomplete
The autocomplete is a normal text input enhanced by a panel of suggested options. It is a 1:1 Angular port of MUI's Autocomplete, composed with Angular Material and driven by a headless signal state machine — filtering, keyboard navigation, ARIA, and single/multiple/free-solo selection all behave as in MUI. It implements ControlValueAccessor, so it plugs into reactive forms. Pick an example from the navigation to see it live.
The widget is useful for two scenarios:
- The value for the textbox must be chosen from a predefined set of allowed values, e.g. a location field must contain a valid location name (a combo box).
- The textbox may contain any arbitrary value, but it is advantageous to suggest possible values, e.g. a search field (free solo).
Basic usage
Import AutocompleteComponent, pass an options array, map each option to its display string with getOptionLabel, and bind the selection with [(value)]. Options can be strings or objects; when an option object has a label property it is used automatically.
import { Component, signal } from '@angular/core';
import { AutocompleteComponent } from '@js-smart/ng-kit';
@Component({
selector: 'app-demo',
imports: [AutocompleteComponent],
template: `
<autocomplete [options]="films" [(value)]="value" label="Movie" placeholder="Pick a film" />
`,
})
export class DemoComponent {
protected readonly films = ['The Godfather', 'Pulp Fiction', 'Inception'];
protected readonly value = signal<string | null>(null);
}Combo box
The value must be chosen from a predefined set of allowed values. Selecting an option updates value; the Combo box and Country select examples show single-select over string and object option lists.
Controlled states
The component has two states that can be controlled independently: the value (the option the user has committed, via Enter or click) and the inputValue (the text shown in the box). They are deliberately independent, as in MUI — bind [(value)], [(inputValue)] and [(open)] to drive them from the outside (see the Controlled example).
Free solo
Set [freeSolo]="true" to allow arbitrary values in the textbox that are not bound to the options — ideal for a search box. Combine it with selectOnFocus, clearOnBlur and handleHomeEndKeys for a "creatable" experience that lets users add new values (see the Free solo example).
Grouped
Provide groupBy to group options under sticky headers; options must be sorted by the same grouping key. Customise the header markup by projecting a *ngGroupHeader template (see the Grouped example).
Disabled options
Use getOptionDisabled to prevent selection of specific options — useful for unavailable time slots or restricted choices.
Asynchronous requests
The component supports both "load on open" and "search as you type". For server-side filtering, pass a pass-through filterOptions (e.g. passThroughFilter) so the component does not filter again, and toggle loading to show loadingText while requests are in flight (see the Asynchronous requests example).
Multiple values
With [multiple]="true" the user can select several values, rendered as removable Material chips. Use filterSelectedOptions to hide already-selected options, and showCheckboxes for a checkbox listbox that stays open after each pick (see the Checkboxes example).
Fixed options
Pass fixedOptions to lock certain chips so they cannot be removed from the selection (see the Fixed tags example).
Limit tags
Use limitTags to cap the number of chips shown when the field is not focused; overflow is summarised as +N (customisable via getLimitTagsText).
Sizes & appearance
size switches between 'medium' and a denser 'small' field, and appearance chooses the Material form-field style ('fill' or 'outline'). See the Sizes & appearances example.
Custom rendering
Every slot is overridable via projected templates: *ngOption (MUI's renderOption, with a query for highlighting), *ngValue (renderValue), *ngGroupHeader (renderGroup), plus *ngPaper, *ngEmpty, *ngLoading, *ngPopupIcon and *ngClearIcon. The Custom rendering example shows query highlighting, custom icons and a custom paper surface.
Custom filter
Use createFilterOptions to tune the default matching: matchFrom ('any' | 'start'), stringify, trim, ignoreCase, ignoreAccents and limit. Pass the result to filterOptions. For fully custom (e.g. fuzzy) matching, provide your own filterOptions function.
Virtualization
Set [virtualize]="true" to render very large option lists efficiently with the CDK virtual scroll; tune itemSize and maxVisibleItems. The Virtualized example renders 10,000 options.
Events
Listen to valueChanged (with a reason: createOption, selectOption, removeOption, clear, blur), inputChanged, opened, closed and highlightChanged. Keyboard handling follows the WAI-ARIA combobox pattern.
Accessibility
The component implements the WAI-ARIA combobox pattern (role="combobox"/listbox/option, aria-activedescendant, full keyboard support). Always provide a label or ariaLabel for a compliant, labelled control.
API
Selectors
autocomplete, lib-autocomplete
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
options | readonly T[] | — (required) | The list of options shown in the panel. |
value | T | T[] | null | null | Two-way selected value (model). An array when multiple. |
inputValue | string | '' | Two-way text shown in the box (model); independent of value. |
open | boolean | false | Two-way popup open state (model). |
getOptionLabel | (option: T) => string | option.label ?? String(option) | Maps an option to its display string. |
getOptionKey | (option: T) => string | number | getOptionLabel | Stable key for an option (trackBy). |
getOptionDisabled | (option: T) => boolean | () => false | Marks individual options as disabled. |
isOptionEqualToValue | (a: T, b: T) => boolean | === | Equality used to match a value against an option. |
groupBy | ((option: T) => string) | null | null | Groups options under headers; options must be pre-sorted by key. |
filterOptions | FilterOptionsFn<T> | createFilterOptions() | Custom filtering function. Pass passThroughFilter for server-side search. |
multiple | boolean | false | Allow selecting several values, rendered as chips. |
freeSolo | boolean | false | Allow arbitrary values not bound to the options. |
disabled | boolean | false | Disable the control (also set via reactive-forms). |
readOnly | boolean | false | Make the control read-only. |
loading | boolean | false | Show a loading indicator and loadingText. |
required | boolean | false | Marks the control required (aria-required). |
invalid | boolean | false | Marks the control invalid (aria-invalid). |
autoComplete | boolean | false | Inline-complete the highlighted label after the cursor. |
autoHighlight | boolean | false | Automatically highlight the first option. |
autoSelect | boolean | false | Select the highlighted option on blur. |
blurOnSelect | boolean | 'mouse' | 'touch' | false | Blur the input after selecting. |
clearOnBlur | boolean | !freeSolo | Clear the input text on blur when there is no value. |
clearOnEscape | boolean | false | Clear the value when Escape is pressed. |
disableClearable | boolean | false | Hide the clear button / prevent clearing. |
disableCloseOnSelect | boolean | false | Keep the popup open after a selection. |
disabledItemsFocusable | boolean | false | Allow keyboard focus to land on disabled options. |
disableListWrap | boolean | false | Prevent wrapping when navigating the listbox. |
disablePortal | boolean | false | Render the popup inline instead of in a CDK overlay. |
filterSelectedOptions | boolean | false | Hide already-selected options from the listbox. |
handleHomeEndKeys | boolean | !freeSolo | Move highlight with Home/End keys. |
includeInputInList | boolean | false | Allow the highlight to move back to the input. |
openOnFocus | boolean | false | Open the popup as soon as the input is focused. |
resetHighlightOnMouseLeave | boolean | false | Reset the highlight when the pointer leaves the list. |
selectOnFocus | boolean | !freeSolo | Select the input text on focus. |
fixedOptions | readonly T[] | [] | Values that cannot be removed while multiple. |
label | string | null | null | Field label (mat-label). |
ariaLabel | string | null | null | Accessible name when no visible label is used. |
placeholder | string | null | null | Input placeholder text. |
size | 'small' | 'medium' | 'medium' | Field density. |
appearance | 'fill' | 'outline' | 'fill' | Material form-field appearance. |
fullWidth | boolean | false | Stretch the field to fill its container. |
limitTags | number | -1 | Max chips shown when unfocused (-1 = all). |
getLimitTagsText | (more: number) => string | (more) => `+${more}` | Label for the truncated-tags summary. |
showCheckboxes | boolean | false | Render a checkbox in front of each option (multiple). |
noOptionsText | string | 'No options' | Message shown when nothing matches. |
loadingText | string | 'Loading…' | Message shown while loading. |
clearText | string | 'Clear' | Accessible label for the clear button. |
openText | string | 'Open' | Accessible label for the toggle button (closed). |
closeText | string | 'Close' | Accessible label for the toggle button (open). |
forcePopupIcon | boolean | 'auto' | 'auto' | Force the dropdown toggle icon on/off. |
virtualize | boolean | false | Virtual-scroll the option list (CDK). |
itemSize | number | 40 | Row height (px) used by virtual scroll. |
maxVisibleItems | number | 8 | Max rows visible before the list scrolls. |
slotProps | NgAutocompleteSlotProps | {} | Per-slot class/attribute pass-through. |
id | string | null | null | Base id used to derive element ids (accessibility). |
Outputs
| Name | Payload | Description |
|---|---|---|
valueChanged | { value; reason; option? } | Selected value changed. reason: createOption | selectOption | removeOption | clear | blur. |
inputChanged | { value: string; reason } | Input text changed. reason: input | reset | clear | blur | selectOption | removeOption. |
opened | OpenReason | Popup opened. reason: toggleInput | focus | input | keyboard. |
closed | CloseReason | Popup closed. reason: toggleInput | escape | selectOption | removeOption | blur. |
highlightChanged | { option: T | null; reason } | Highlighted option changed. reason: keyboard | mouse | auto | touch. |
Content template directives
Project a template to override a slot; each receives a typed context. These map to MUI's render props and slots.
| Directive | MUI equivalent | Context / purpose |
|---|---|---|
*ngOption | renderOption | Custom option row. Context: $implicit (option), option, highlighted, selected, query. |
*ngValue | renderValue | Custom chip / selected-value rendering. Context: $implicit, index, label, disabled, fixed, focused, remove(). |
*ngGroupHeader | renderGroup | Custom group header. Context: $implicit (group name), count. |
*ngPaper | slots.paper | Custom popup surface wrapping the listbox. Context: $implicit (listbox template). |
*ngEmpty | noOptionsText | Custom "no options" content. |
*ngLoading | loadingText | Custom loading content. |
*ngPopupIcon | popupIcon | Custom dropdown toggle icon. |
*ngClearIcon | clearIcon | Custom clear-button icon. |
Filter helpers
createFilterOptions(config?) builds a filterOptions function; defaultFilterOptions is the default, and passThroughFilter disables client-side filtering (for server-side search). Config options:
| Option | Type | Default | Description |
|---|---|---|---|
matchFrom | 'any' | 'start' | 'any' | Match anywhere in the string, or only at the start. |
stringify | (option: T) => string | getOptionLabel | Turn an option into the string that gets matched. |
ignoreCase | boolean | true | Lowercase both sides before comparing. |
ignoreAccents | boolean | true | Strip diacritics before comparing. |
trim | boolean | false | Trim trailing whitespace off the query. |
limit | number | null | null | Cap the number of suggestions returned. |
Per-element class/attribute overrides are available via slotProps (mirroring MUI's slotProps) for the root, input, listbox, paper, clearIndicator and popupIndicator slots. The headless NgAutocompleteState and all types are exported for advanced use.
