Autocomplete
<oge-autocomplete> is a text editor with a filtered suggestion list: the committed value is the string itself, suggestions open while typing and picking one writes its display text. Use it when free text is valid and the list is assistance — reach for <oge-select-box> when the value must be an item.
Basic usage
Type to see suggestions (from minSearchLength = 1 character on). Enter or blur commits the text; picking a suggestion commits its display text. The chevron and field-click opening are off by default.
''import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeAutocomplete } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeAutocomplete],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-autocomplete
label="City"
[items]="cities"
[(value)]="cityName"
/>
`,
})
export class Demo {
protected readonly cities = ['Ankara', 'Berlin', 'Lisbon', 'Oslo', 'Tokyo'];
// the committed value is the TEXT itself, not an item value
protected readonly cityName = signal('');
}Suggestion tuning
minSearchLength keeps the list closed until enough is typed, maxItemCount caps it (default 10), searchMode switches contains/startswith and searchTimeout debounces the filter. groupBy and itemTemplate work exactly like the select box.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeAutocomplete } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeAutocomplete],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-autocomplete
label="Product"
[items]="products"
displayExpr="name"
searchMode="startswith"
[minSearchLength]="2"
[maxItemCount]="5"
[(value)]="productName"
/>
`,
})
export class Demo {
protected readonly products = [
{ id: 1, name: 'Aurora Display' },
{ id: 2, name: 'Aurora Keyboard' },
{ id: 3, name: 'Nimbus Router' },
];
protected readonly productName = signal('');
}Force selection
forceSelection turns free text off: on blur, text that matches no suggestion reverts to the last committed value, and an exact match resolves to the item with its canonical casing. selectionChanged reports the picked item — or null once the text diverges.
nullimport { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeAutocomplete } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeAutocomplete],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-autocomplete
label="Assignee"
[items]="users"
displayExpr="name"
[forceSelection]="true"
[(value)]="assigneeName"
(selectionChanged)="assignee = $event.item"
/>
<!-- non-matching text reverts on blur; an exact match resolves
to the item (canonical casing) and fires selectionChanged -->
`,
})
export class Demo {
protected readonly users = [
{ id: 1, name: 'Elif Kaya' },
{ id: 2, name: 'Mert Demir' },
];
protected readonly assigneeName = signal('');
protected assignee: unknown = null;
}Virtual scrolling
virtualScroll windows the dropdown: 10 000 rows here, ~15 in the DOM inside a full-height spacer. Available on the select box, tag box and autocomplete alike — pass true or { itemHeight, overscan }. Raise maxItemCount on the autocomplete, which otherwise caps the list at 10. Rows get a fixed size-matched height; groupBy/wrapItemText are ignored while active.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeAutocomplete, OgeSelectBox } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeAutocomplete, OgeSelectBox],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- 10 000 rows, ~15 in the DOM -->
<oge-autocomplete
label="Account"
[items]="accounts"
[virtualScroll]="true"
[maxItemCount]="10000"
[(value)]="accountName"
/>
<oge-select-box
label="Account"
[items]="accounts"
[searchEnabled]="true"
[virtualScroll]="{ overscan: 6 }"
[(value)]="accountId"
/>
`,
})
export class Demo {
protected readonly accounts = Array.from(
{ length: 10000 },
(_, index) => `Account ${index + 1}`,
);
protected readonly accountName = signal('');
protected readonly accountId = signal<unknown>(null);
}Lazy & server-side data
A function as [items] loads once on first open with localized loading/error rows. For fully server-driven suggestions, listen to searchChanged, keep [items] in sync and flag [loading] while the request runs.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeAutocomplete } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeAutocomplete],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-autocomplete
label="Repository"
[items]="loadRepos"
[(value)]="repo"
/>
<!-- or fully server-side: keep [items] in sync yourself -->
<oge-autocomplete
[items]="serverItems()"
[loading]="serverLoading()"
[searchTimeout]="300"
(searchChanged)="queryServer($event.text)"
/>
`,
})
export class Demo {
protected readonly repo = signal('');
// invoked once, on first open
protected readonly loadRepos = (): Promise<string[]> =>
fetch('/api/repos').then((response) => response.json());
protected readonly serverItems = signal<string[]>([]);
protected readonly serverLoading = signal(false);
protected queryServer(text: string): void {
this.serverLoading.set(true);
fetch(`/api/repos?q=${encodeURIComponent(text)}`)
.then((response) => response.json())
.then((items: string[]) => this.serverItems.set(items))
.finally(() => this.serverLoading.set(false));
}
}Field chrome
The shared chrome applies unchanged: label modes, sizes, styling modes, clear button, hints and validation. showDropDownButton + openOnFieldClick opt into select-box-like opening.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeAutocomplete } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeAutocomplete],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-autocomplete
label="Tag"
labelMode="floating"
[showClearButton]="true"
[showDropDownButton]="true"
[openOnFieldClick]="true"
hint="Start typing to search"
[items]="tags"
[(value)]="tag"
/>
`,
})
export class Demo {
protected readonly tags = ['angular', 'signals', 'zoneless'];
protected readonly tag = signal('');
}Keyboard & accessibility
WAI-ARIA combobox with aria-autocomplete="list" and aria-activedescendant — DOM focus never leaves the input. No suggestion is auto-activated: Enter without arrowing commits the typed text.
- ↓/↑ open the list and move the active suggestion; PgUp/PgDn jump ten.
- Enter commits the active suggestion — or the raw text when none is active. Esc closes the list first, then reverts the typed text.
- Typing below
minSearchLengthcloses the list; deleting all text keeps the last committed value until blur.