Autocomplete
Autocomplete input and dropdown selection with filtering options.
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { HlmAutocomplete } from '@spartan-ng/helm/autocomplete';
@Component({
selector: 'spartan-autocomplete-preview',
imports: [HlmAutocomplete],
template: `
<hlm-autocomplete [filteredOptions]="filteredOptions()" [(search)]="search" />
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AutocompletePreview {
private readonly _options: string[] = [
'Marty McFly',
'Doc Brown',
'Biff Tannen',
'George McFly',
'Jennifer Parker',
'Emmett Brown',
'Einstein',
'Clara Clayton',
'Needles',
'Goldie Wilson',
'Marvin Berry',
'Lorraine Baines',
'Strickland',
];
public readonly search = signal('');
public readonly filteredOptions = computed(() =>
this._options.filter((option) => option.toLowerCase().includes(this.search().toLowerCase())),
);
}
Installation
The Autocomplete component is built with the Popover and the Command components.
npx nx g @spartan-ng/cli:ui autocomplete
ng g @spartan-ng/cli:ui autocomplete
Usage
import { HlmAutocomplete } from '@spartan-ng/helm/autocomplete';
<hlm-autocomplete [options]="options" />
Brain API
BrnAutocompleteEmpty
Selector: [brnAutocompleteEmpty]
BrnAutocompleteGroup
Selector: [brnAutocompleteGroup]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | string | `brn-autocomplete-group-${++BrnAutocompleteGroup._id}` | The id of the autocomplete list |
BrnAutocompleteItem
Selector: button[brnAutocompleteItem]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | unknown | `brn-autocomplete-item-${++BrnAutocompleteItem._id}` | A unique id for the item |
value* (required) | T | - | The value this item represents. |
disabled | boolean | false | Whether the item is disabled. |
Outputs
Prop | Type | Default | Description |
---|---|---|---|
selected | void | - | Emits when the item is selected. |
BrnAutocompleteList
Selector: [brnAutocompleteList]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | string | `brn-autocomplete-list-${++BrnAutocompleteList._id}` | The id of the command list |
BrnAutocompleteSearchInput
Selector: input[brnAutocompleteSearchInput]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
value | string | - | The initial value of the search input |
BrnAutocomplete
Selector: [brnAutocomplete]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | string | `brn-autocomplete-${++BrnAutocomplete._id}` | The id of the autocomplete |
Outputs
Prop | Type | Default | Description |
---|---|---|---|
valueChange | T | - | when the selection has changed |
Helm API
HlmAutocompleteEmpty
Selector: [hlmAutocompleteEmpty]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmAutocompleteGroup
Selector: hlm-autocomplete-group
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | The user defined class |
HlmAutocompleteItem
Selector: button[hlm-autocomplete-item]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | The user defined class |
HlmAutocompleteList
Selector: hlm-autocomplete-list
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | The user defined class |
HlmAutocompleteSearchInput
Selector: input[hlm-autocomplete-search-input]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | The user defined class |
HlmAutocompleteSearch
Selector: hlm-autocomplete-search
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | The user defined class |
HlmAutocompleteTrigger
Selector: [hlmAutocompleteTrigger]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
disabledTrigger | boolean | false | Whether the trigger is disabled. |
HlmAutocomplete
Selector: hlm-autocomplete
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | The user defined class |
autocompleteListClass | ClassValue | - | Custom class for the autocomplete list. |
autocompleteEmptyClass | ClassValue | - | Custom class for the empty and loading state container. |
filteredOptions | T[] | [] | The list of filtered options to display in the autocomplete. |
value | T | - | The selected value. |
search | string | - | The search query. |
transformValueToSearch | (value: T) => string | this._config.transformValueToSearch | Function to transform an option value to a search string. Defaults to identity function for strings. |
optionTemplate | TemplateRef<HlmAutocompleteOption<T>> | - | Optional template for rendering each option. |
loading | boolean | false | Whether the autocomplete is in a loading state. |
searchPlaceholderText | unknown | Select an option | Placeholder text for the input field. |
loadingText | unknown | Loading options... | Text to display when loading options. |
emptyText | unknown | No options found | Text to display when no options are found. |
ariaLabelToggleButton | string | Toggle options | Aria label for the toggle button. |
inputId | string | `hlm-autocomplete-input-${++HlmAutocomplete._id}` | The id of the input field. |
disabled | boolean | false | Whether the autocomplete is disabled. |
Outputs
Prop | Type | Default | Description |
---|---|---|---|
valueChange | T | null | - | Emitted when the selected value changes. |
searchChange | string | - | Emitted when the search query changes. |
Examples
Objects
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { HlmAutocomplete } from '@spartan-ng/helm/autocomplete';
import { provideHlmAutocompleteConfig } from 'libs/helm/autocomplete/src/lib/hlm-autocomplete.token';
type Country = {
name: string;
code: string;
flag: string;
};
@Component({
selector: 'spartan-autocomplete-countries',
imports: [HlmAutocomplete],
template: `
<hlm-autocomplete [filteredOptions]="filteredCountries()" [optionTemplate]="option" [(search)]="search" />
<ng-template #option let-option>{{ option.flag }} {{ option.name }}</ng-template>
`,
providers: [
provideHlmAutocompleteConfig({
transformValueToSearch: (value: Country) => `${value.flag} ${value.name}`,
}),
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AutocompleteCountries {
private readonly _countries: Country[] = [
{ name: 'Argentina', code: 'AR', flag: '🇦🇷' },
{ name: 'Australia', code: 'AU', flag: '🇦🇺' },
{ name: 'Belgium', code: 'BE', flag: '🇧🇪' },
{ name: 'Brazil', code: 'BR', flag: '🇧🇷' },
{ name: 'Canada', code: 'CA', flag: '🇨🇦' },
{ name: 'China', code: 'CN', flag: '🇨🇳' },
{ name: 'France', code: 'FR', flag: '🇫🇷' },
{ name: 'Germany', code: 'DE', flag: '🇩🇪' },
{ name: 'India', code: 'IN', flag: '🇮🇳' },
{ name: 'Italy', code: 'IT', flag: '🇮🇹' },
{ name: 'Japan', code: 'JP', flag: '🇯🇵' },
{ name: 'Mexico', code: 'MX', flag: '🇲🇽' },
{ name: 'Netherlands', code: 'NL', flag: '🇳🇱' },
{ name: 'Norway', code: 'NO', flag: '🇳🇴' },
{ name: 'Russia', code: 'RU', flag: '🇷🇺' },
{ name: 'South Africa', code: 'ZA', flag: '🇿🇦' },
{ name: 'South Korea', code: 'KR', flag: '🇰🇷' },
{ name: 'Spain', code: 'ES', flag: '🇪🇸' },
{ name: 'Sweden', code: 'SE', flag: '🇸🇪' },
{ name: 'Switzerland', code: 'CH', flag: '🇨ðŸ‡' },
{ name: 'United Kingdom', code: 'GB', flag: '🇬🇧' },
{ name: 'United States', code: 'US', flag: '🇺🇸' },
];
public readonly search = signal<string>('');
public readonly filteredCountries = computed(() =>
this._countries.filter(
(country) =>
country.name.toLowerCase().includes(this.search().toLowerCase()) ||
`${country.flag} ${country.name}`.toLowerCase().includes(this.search().toLowerCase()),
),
);
}
Asynchronous
import { ChangeDetectionStrategy, Component, resource, signal } from '@angular/core';
import { HlmAutocomplete } from '@spartan-ng/helm/autocomplete';
import { HlmSpinner } from '@spartan-ng/helm/spinner';
@Component({
selector: 'spartan-autocomplete-async',
imports: [HlmAutocomplete, HlmSpinner],
template: `
<hlm-autocomplete [filteredOptions]="options.value()" [loading]="options.isLoading()" [(search)]="search">
<hlm-spinner loading class="size-6" />
</hlm-autocomplete>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AutocompleteAsync {
public readonly search = signal('');
public options = resource({
defaultValue: [],
request: () => ({ search: this.search() }),
loader: async (params) => {
const search = params.request.search;
if (search.length === 0) {
return [];
}
// Simulate empty state
if (search === 'empty') {
return [];
}
// DEV - call your API or 3rd party service here
// simulate async
return new Promise<string[]>((resolve) => {
setTimeout(() => {
const newOptions = Array.from({ length: 15 }, (_, i) => `${search}-${i + 1}`);
resolve(newOptions);
}, 500);
});
},
});
}
Form
import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { HlmAutocomplete } from '@spartan-ng/helm/autocomplete';
import { HlmButton } from '@spartan-ng/helm/button';
import { HlmLabel } from '@spartan-ng/helm/label';
@Component({
selector: 'spartan-autocomplete-form',
imports: [HlmAutocomplete, ReactiveFormsModule, HlmButton, HlmLabel],
template: `
<form [formGroup]="form" (ngSubmit)="submit()" class="space-y-8">
<div class="flex flex-col gap-2">
<label for="autocomplete" hlmLabel class="px-1">Choose your favorite character</label>
<hlm-autocomplete
inputId="autocomplete"
[filteredOptions]="filteredOptions()"
[(search)]="search"
formControlName="option"
/>
</div>
<button type="submit" hlmBtn>Submit</button>
</form>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AutocompleteForm {
private readonly _formBuilder = inject(FormBuilder);
private readonly _options: string[] = [
'Marty McFly',
'Doc Brown',
'Biff Tannen',
'George McFly',
'Jennifer Parker',
'Emmett Brown',
'Einstein',
'Clara Clayton',
'Needles',
'Goldie Wilson',
'Marvin Berry',
'Lorraine Baines',
'Strickland',
];
public readonly search = signal('');
public form = this._formBuilder.group({
option: [null, Validators.required],
});
public readonly filteredOptions = computed(() =>
this._options.filter((option) => option.toLowerCase().includes(this.search().toLowerCase())),
);
submit() {
console.log(this.form.value);
}
}