- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Dropdown Menu
- Empty
- Field
- Form Field
- Hover Card
- Icon
- Input Group
- Input OTP
- Input
- Item
- Kbd
- Label
- Menubar
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner (Toast)
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
Autocomplete
Autocomplete input and dropdown selection with filtering options.
import { 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" />
`,
})
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 component.
ng g @spartan-ng/cli:ui autocomplete
npx nx g @spartan-ng/cli:ui autocomplete
Usage
import { HlmAutocompleteImports } from '@spartan-ng/helm/autocomplete';<hlm-autocomplete [options]="options" />Examples
Custom Config
Use provideHlmAutocompleteConfig to define custom configurations for the autocomplete component. This is especially useful when the autocomplete's filteredOptions contain objects rather than plain strings.
transformOptionToString: (option: T) => string;defines how an option should be transformed into the string displayed in the dropdown list.transformValueToSearch: (option: T) => string;defines how the selected option should be transformed into the string written to the search input.
You can customize a specific instance of hlm-autocomplete by passing transformOptionToString and transformValueToSearch directly as inputs. This allows you to modify the behavior for just that instance, without affecting all autocompletes configured via provideHlmAutocompleteConfig .
import { Component, computed, signal } from '@angular/core';
import { HlmAutocompleteImports } 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-config',
imports: [HlmAutocompleteImports],
providers: [
provideHlmAutocompleteConfig({
transformOptionToString: (option: Country) => `${option.flag} ${option.name}`,
transformValueToSearch: (option: Country) => `${option.flag} ${option.name}`,
}),
],
template: `
<hlm-autocomplete [filteredOptions]="filteredCountries()" [(search)]="search" />
`,
})
export class AutocompleteConfig {
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()),
),
);
}Custom Option Template
You can customize the rendering of each option in the dropdown list by using the ng-template with the optionTemplate input. This is especially useful when filteredOptions are objects instead of simple strings, or when you want to display additional content such as icons, descriptions, or custom formatting alongside the option text.
import { Component, computed, signal } from '@angular/core';
import { HlmAutocompleteImports } 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: [HlmAutocompleteImports],
providers: [
provideHlmAutocompleteConfig({
transformValueToSearch: (option: Country) => `${option.flag} ${option.name}`,
}),
],
template: `
<hlm-autocomplete [filteredOptions]="filteredCountries()" [optionTemplate]="option" [(search)]="search" />
<!-- custom option template with access to the option item -->
<ng-template #option let-option>{{ option.flag }} {{ option.name }}</ng-template>
`,
})
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 { Component, resource, signal } from '@angular/core';
import { HlmAutocompleteImports } from '@spartan-ng/helm/autocomplete';
import { HlmSpinnerImports } from '@spartan-ng/helm/spinner';
@Component({
selector: 'spartan-autocomplete-async',
imports: [HlmAutocompleteImports, HlmSpinnerImports],
template: `
<hlm-autocomplete [filteredOptions]="options.value()" [loading]="options.isLoading()" [(search)]="search">
<hlm-spinner loading class="size-6" />
</hlm-autocomplete>
`,
})
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 { Component, computed, inject, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { HlmAutocompleteImports } from '@spartan-ng/helm/autocomplete';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmLabelImports } from '@spartan-ng/helm/label';
@Component({
selector: 'spartan-autocomplete-form',
imports: [HlmAutocompleteImports, ReactiveFormsModule, HlmButtonImports, HlmLabelImports],
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>
`,
})
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);
}
}Transform option value
Use transformOptionToValue to transform an object value into a single value and use displayWith to define how the selected value is displayed in the search input.
In the following example, a list with id: string, label: string objects is used as options. The selected option is transformed to its id using transformOptionToValue and the label is displayed in the search input using displayWith .
import { Component, computed, inject, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { HlmAutocompleteImports, provideHlmAutocompleteConfig } from '@spartan-ng/helm/autocomplete';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmLabelImports } from '@spartan-ng/helm/label';
type Item = {
id: string;
label: string;
};
@Component({
selector: 'spartan-autocomplete-transform-option-value',
imports: [HlmAutocompleteImports, ReactiveFormsModule, HlmButtonImports, HlmLabelImports],
providers: [
provideHlmAutocompleteConfig({
transformOptionToString: (option: Item) => option.label,
}),
],
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"
formControlName="option"
[transformOptionToValue]="_transformOptionValue"
[displayWith]="_displayWith"
[filteredOptions]="filteredOptions()"
[(search)]="search"
showClearBtn
/>
</div>
<button type="submit" hlmBtn>Submit</button>
</form>
`,
})
export class AutocompleteTransformOptionValue {
private readonly _formBuilder = inject(FormBuilder);
private readonly _options: Item[] = [
{ id: '1', label: 'Marty McFly' },
{ id: '2', label: 'Doc Brown' },
{ id: '3', label: 'Biff Tannen' },
{ id: '4', label: 'George McFly' },
{ id: '5', label: 'Jennifer Parker' },
{ id: '6', label: 'Emmett Brown' },
{ id: '7', label: 'Einstein' },
{ id: '8', label: 'Clara Clayton' },
{ id: '9', label: 'Needles' },
{ id: '10', label: 'Goldie Wilson' },
{ id: '11', label: 'Marvin Berry' },
{ id: '12', label: 'Lorraine Baines' },
{ id: '13', label: 'Strickland' },
];
protected _transformOptionValue = (option: Item) => option.id;
protected _displayWith = (id: string) => this._options.find((option) => option.id === id)?.label ?? '';
public readonly search = signal('');
public form = this._formBuilder.group({
option: ['10', Validators.required],
});
public readonly filteredOptions = computed(() => {
return this._options.filter((option) => option.label.toLowerCase().includes(this.search().toLowerCase()));
});
submit() {
console.log(this.form.value.option);
}
}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]
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 |
| selectionCleared | void | - | when the selection has been cleared |
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 |
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 |
| autocompleteSearchClass | ClassValue | - | Custom class for the autocomplete search container. |
| autocompleteInputClass | ClassValue | - | Custom class for the autocomplete input. |
| autocompleteListClass | ClassValue | - | Custom class for the autocomplete list. |
| autocompleteItemClass | ClassValue | - | Custom class for each autocomplete item. |
| autocompleteEmptyClass | ClassValue | - | Custom class for the empty and loading state container. |
| filteredOptions | T[] | [] | The list of filtered options to display in the autocomplete. |
| debounceTime | number | this._config.debounceTime | Debounce time in milliseconds for the search input. |
| transformValueToSearch | (option: T) => string | this._config.transformValueToSearch | Function to transform an option value to a search string. Defaults to identity function for strings. |
| requireSelection | boolean | this._config.requireSelection | Whether selection of an option is required. |
| transformOptionToString | (option: T) => string | this._config.transformOptionToString | Function to transform an option value to a display string. Defaults to identity function for strings. |
| transformOptionToValue | ((option: T) => V) | undefined | this._config.transformOptionToValue | Function to transform the object to the value. |
| displayWith | ((value: V) => string) | undefined | undefined | Function to display the selected value as a string. |
| optionTemplate | TemplateRef<HlmAutocompleteOption<T>> | - | Optional template for rendering each option. |
| loading | boolean | false | Whether the autocomplete is in a loading state. |
| showClearBtn | boolean | this._config.showClearBtn | Whether to show the clear button when a option is selected. |
| 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 | unknown | Toggle options | Aria label for the toggle button. |
| inputId | unknown | `hlm-autocomplete-input-${++HlmAutocomplete._id}` | The id of the input field. |
| disabled | boolean | false | Whether the autocomplete is disabled. |
| value | T | V | - | The selected value. |
| search | string | - | The search query. |
Outputs
| Prop | Type | Default | Description |
|---|---|---|---|
| valueChange | T | V | null | - | Emitted when the selected value changes. |
| searchChange | string | - | Emitted when the search query changes. |
| valueChanged | T | V | - | The selected value. |
| searchChanged | string | - | The search query. |
On This Page