NG Kit

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.

typescript
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

NameTypeDefaultDescription
optionsreadonly T[]— (required)The list of options shown in the panel.
valueT | T[] | nullnullTwo-way selected value (model). An array when multiple.
inputValuestring''Two-way text shown in the box (model); independent of value.
openbooleanfalseTwo-way popup open state (model).
getOptionLabel(option: T) => stringoption.label ?? String(option)Maps an option to its display string.
getOptionKey(option: T) => string | numbergetOptionLabelStable key for an option (trackBy).
getOptionDisabled(option: T) => boolean() => falseMarks individual options as disabled.
isOptionEqualToValue(a: T, b: T) => boolean===Equality used to match a value against an option.
groupBy((option: T) => string) | nullnullGroups options under headers; options must be pre-sorted by key.
filterOptionsFilterOptionsFn<T>createFilterOptions()Custom filtering function. Pass passThroughFilter for server-side search.
multiplebooleanfalseAllow selecting several values, rendered as chips.
freeSolobooleanfalseAllow arbitrary values not bound to the options.
disabledbooleanfalseDisable the control (also set via reactive-forms).
readOnlybooleanfalseMake the control read-only.
loadingbooleanfalseShow a loading indicator and loadingText.
requiredbooleanfalseMarks the control required (aria-required).
invalidbooleanfalseMarks the control invalid (aria-invalid).
autoCompletebooleanfalseInline-complete the highlighted label after the cursor.
autoHighlightbooleanfalseAutomatically highlight the first option.
autoSelectbooleanfalseSelect the highlighted option on blur.
blurOnSelectboolean | 'mouse' | 'touch'falseBlur the input after selecting.
clearOnBlurboolean!freeSoloClear the input text on blur when there is no value.
clearOnEscapebooleanfalseClear the value when Escape is pressed.
disableClearablebooleanfalseHide the clear button / prevent clearing.
disableCloseOnSelectbooleanfalseKeep the popup open after a selection.
disabledItemsFocusablebooleanfalseAllow keyboard focus to land on disabled options.
disableListWrapbooleanfalsePrevent wrapping when navigating the listbox.
disablePortalbooleanfalseRender the popup inline instead of in a CDK overlay.
filterSelectedOptionsbooleanfalseHide already-selected options from the listbox.
handleHomeEndKeysboolean!freeSoloMove highlight with Home/End keys.
includeInputInListbooleanfalseAllow the highlight to move back to the input.
openOnFocusbooleanfalseOpen the popup as soon as the input is focused.
resetHighlightOnMouseLeavebooleanfalseReset the highlight when the pointer leaves the list.
selectOnFocusboolean!freeSoloSelect the input text on focus.
fixedOptionsreadonly T[][]Values that cannot be removed while multiple.
labelstring | nullnullField label (mat-label).
ariaLabelstring | nullnullAccessible name when no visible label is used.
placeholderstring | nullnullInput placeholder text.
size'small' | 'medium''medium'Field density.
appearance'fill' | 'outline''fill'Material form-field appearance.
fullWidthbooleanfalseStretch the field to fill its container.
limitTagsnumber-1Max chips shown when unfocused (-1 = all).
getLimitTagsText(more: number) => string(more) => `+${more}`Label for the truncated-tags summary.
showCheckboxesbooleanfalseRender a checkbox in front of each option (multiple).
noOptionsTextstring'No options'Message shown when nothing matches.
loadingTextstring'Loading…'Message shown while loading.
clearTextstring'Clear'Accessible label for the clear button.
openTextstring'Open'Accessible label for the toggle button (closed).
closeTextstring'Close'Accessible label for the toggle button (open).
forcePopupIconboolean | 'auto''auto'Force the dropdown toggle icon on/off.
virtualizebooleanfalseVirtual-scroll the option list (CDK).
itemSizenumber40Row height (px) used by virtual scroll.
maxVisibleItemsnumber8Max rows visible before the list scrolls.
slotPropsNgAutocompleteSlotProps{}Per-slot class/attribute pass-through.
idstring | nullnullBase id used to derive element ids (accessibility).

Outputs

NamePayloadDescription
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.
openedOpenReasonPopup opened. reason: toggleInput | focus | input | keyboard.
closedCloseReasonPopup 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.

DirectiveMUI equivalentContext / purpose
*ngOptionrenderOptionCustom option row. Context: $implicit (option), option, highlighted, selected, query.
*ngValuerenderValueCustom chip / selected-value rendering. Context: $implicit, index, label, disabled, fixed, focused, remove().
*ngGroupHeaderrenderGroupCustom group header. Context: $implicit (group name), count.
*ngPaperslots.paperCustom popup surface wrapping the listbox. Context: $implicit (listbox template).
*ngEmptynoOptionsTextCustom "no options" content.
*ngLoadingloadingTextCustom loading content.
*ngPopupIconpopupIconCustom dropdown toggle icon.
*ngClearIconclearIconCustom 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:

OptionTypeDefaultDescription
matchFrom'any' | 'start''any'Match anywhere in the string, or only at the start.
stringify(option: T) => stringgetOptionLabelTurn an option into the string that gets matched.
ignoreCasebooleantrueLowercase both sides before comparing.
ignoreAccentsbooleantrueStrip diacritics before comparing.
trimbooleanfalseTrim trailing whitespace off the query.
limitnumber | nullnullCap 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.