GUILD OF GLEKS UIv21.4.4

gog-autocomplete

Autocomplete

A text field that suggests options as you type. It shares GogDropdownBase with Select — the same option accessors, placement, float label, error state and ControlValueAccessor — but its trigger is a real <input>, which is what makes it a separate control rather than a mode of the select.

Overview

Import the component and drop it into a template.

typescript
import { AutocompleteComponent } from '@guildofgleks/ui';

@Component({
  // ...
  imports: [AutocompleteComponent],
})

Basic usage — type a letter or two:

<gog-autocomplete
  label="City"
  placeholder="Start typing…"
  [options]="cities"
  [(value)]="city"
/>

Server-backed suggestions

Two things shape how the panel behaves before a query even runs. openOnFocus21.3.1 — on by default — opens the panel with the full option list the moment the field is focused, instead of waiting for minLength characters: for a short, known list that is the difference between a combobox and a text field the user has to guess at. Turn it off per instance, or app-wide with GOG_CONFIG.autocomplete.openOnFocus, to keep the older behaviour of showing nothing until something is typed.

gogLoadMore21.3.1 fires when the panel is scrolled to its end. Fetch the next page and append it to options — that is how a large or server-backed source is paged, with no virtual scroller involved.

gogSearch is debounced (searchDebounce, 300 ms by default), so a lookup fires once the typing settles rather than on every keystroke. Set [filterLocal]="false" alongside it: the server has already filtered, and filtering its answer a second time against the same query is the classic double-filtering bug — it silently drops rows the server matched on a field this component cannot see.

This demo fakes a 400 ms round trip. It also matches on the country, which local filtering would throw away — type germany to see it.

<gog-autocomplete
  label="City"
  [options]="results()"
  [loading]="loading()"
  [filterLocal]="false"
  [searchDebounce]="300"
  [minLength]="2"
  (gogSearch)="search($event)"
  [(value)]="city"
/>

Examples

Your own objects

optionLabel, optionValue and optionDisabled take a property path (dot-paths included) or a function. Set [optionValue]="null" and the control hands back the option object — the same reference you passed in — instead of an id.

<!-- optionValue="null" hands back the option object itself, not an id. -->
<gog-autocomplete
  label="City"
  optionLabel="name"
  [optionValue]="null"
  [options]="cities"
  [(value)]="cityObject"
/>

Custom suggestion rows

A gogDropdownOption template replaces one row, with the option itself plus selected, disabled and the resolved label in its context — so a custom row can decorate the label rather than re-derive it.

<gog-autocomplete label="City" [options]="cities" [(value)]="slotCity">
  <ng-template gogDropdownOption let-option let-label="label">
    <strong>{{ label }}</strong>
    <small>{{ option.country }}</small>
  </ng-template>
</gog-autocomplete>

Free text (forceSelection)

On by default, the field always ends up reflecting a real selection: editing is treated as transient, so value survives keystrokes and Escape or blur snaps the text back to it. Turn it off for a create-as-you-type flow — the text is then left alone on blur and value is dropped as soon as it stops matching, so the two never disagree. Read what was typed from gogSearch, not from value.

<!-- forceSelection="false": what was typed is itself meaningful. -->
<gog-autocomplete
  label="Tag"
  [forceSelection]="false"
  [options]="cities"
  (gogSearch)="draft.set($event)"
  [(value)]="freeText"
/>

Accessibility

The <input> keeps DOM focus the whole time and the highlighted suggestion is pointed at with aria-activedescendant — where a listbox would move focus onto the option itself. That is the difference that makes this a combobox rather than a select, and it is why typing keeps working while the panel is open.

Arrow keys move the highlight, Enter picks it, Escape closes the panel. Give the field a label or an ariaLabel; use inputId if you are wiring your own <label for="…">.

API Reference

Inputs — autocomplete's own

NameTypeDefaultDescription
openOnFocus21.3.1boolean | undefinedundefinedWhether focusing the field opens the panel immediately with the full option list, rather than waiting for minLength characters. Unset, falls back to GOG_CONFIG.autocomplete.openOnFocus, then to true.
valueTValuenullThe selected value — whatever optionValue resolves to. Two-way bindable with [(value)].
filterLocalbooleantrueWhether options are narrowed in the browser as you type. Turn it OFF when gogSearch fetches an already-filtered list: filtering that answer a second time is the classic double-filtering bug, and it silently drops rows the server matched on a field this component cannot see.
minLengthnumberGOG_CONFIG.autocomplete.minLength ?? 1How many characters before the panel opens at all.
searchDebouncenumberGOG_CONFIG.autocomplete.searchDebounce ?? 300Milliseconds of quiet before gogSearch fires. 0 emits on every keystroke.
loadingbooleanfalseShows a spinner in the trailing slot, for a server-backed source still fetching.
emptyMessagestring'No matches'Shown in place of the list when nothing matches.
forceSelectionbooleantrueOn, the field always ends up reflecting a real selection — editing is transient and Escape or blur snaps the text back. Off, the typed text is itself meaningful (a create-as-you-type flow): it survives blur and value is dropped as soon as it stops matching, so the two never disagree.
inputIdstring''id for the inner <input>, for an external <label for="…">.

Inputs — shared with Select

These come from GogDropdownBase and behave exactly as they do on Select. The one exception is filter: an autocomplete's trigger already is the search box, so the panel never gets a second one — filterMatch still applies, though, since it plugs into filterLocal's own matching rather than the panel's search box.

NameTypeDefaultDescription
optionsTOption[][]The suggestions. Your own objects.
optionLabelstring | ((o: TOption) => string)'name'Property path (dot-paths included) or function producing an option’s label.
optionValuestring | ((o: TOption) => unknown) | null'id'What the control emits. null emits the option object itself.
optionDisabledstring | ((o: TOption) => boolean)'disabled'Which suggestions cannot be picked.
filterMatch((option: TOption, query: string) => boolean) | nullnullHow filterLocal matches an option against the typed text. Left null, the resolved optionLabel is matched case-insensitively as a substring.
label / placeholder / ariaLabelstring'' / 'Select...' / ''Field label, placeholder and accessible name.
clearable / clearAriaLabelboolean / stringGOG_CONFIG.control.clearable ?? false / 'Clear selection'A clear button that appears only once there is something to clear.
floatLabel / floatLabelShowPlaceholder'none' | 'in' | 'on' | 'over' / booleanGOG_CONFIG.floatLabel.* ?? 'none' / falseFloat-label variant and whether the placeholder reappears once it has floated.
errorMessage / errorDisplaystring / 'manual' | 'auto''' / GOG_CONFIG.control.errorDisplay ?? 'manual'Validation message, shown manually or derived from the bound form control.
size / disabled / fullWidth / minWidthGogSize / boolean / boolean / string | nullGOG_CONFIG.control.size ?? 'md' / false / true / nullDensity, disabled state, and how the field sizes itself.
appendToBody / dropdownDirection / dropdownWidth / dropdownMaxHeight / dropdownZIndexboolean / GogDropdownDirection / string | null / string | null / number | nullGOG_CONFIG.dropdown.* ?? component defaultsPanel placement. appendToBody renders it into <body> so an overflow-clipped ancestor cannot cut it off.

Outputs

NamePayloadDescription
gogSearchstringThe current query, debounced. Wire a server-side lookup to this.
gogLoadMore21.3.1voidThe panel was scrolled to the end. Fetch the next page and append it to options — this is how a large or server-backed option source is paged without a virtual scroller.
valueChangeTValueEmitted when the selection changes. Comes from the value model input.

Content slots

DirectiveContextDescription
gogDropdownOption$implicit, selected, disabled, labelReplaces one suggestion row.

Styling Tokens

Every CSS custom property the autocomplete paints with. Override any of them — on a single instance, a subtree, or a theme — to restyle it. See the Theming guide for the full token-layering model, or the Theme Generator to tweak these live.

TokenDescription
--gog-autocomplete-label-colorField label color.
--gog-autocomplete-field-bg / -border-color / -text-colorField surface, border and text.
--gog-autocomplete-radius / -min-widthField corner radius and the floor an auto-width field cannot collapse past.
--gog-autocomplete-focus-ring-color / -focus-ring-width / -hover-border-colorFocus and hover states.
--gog-autocomplete-panel-bg / -panel-border-color / -panel-shadow / -panel-max-heightSuggestion panel surface and height cap.
--gog-autocomplete-option-hover-bg / -option-selected-bg / -option-heightSuggestion row states and row height.
--gog-autocomplete-empty-color / -spinner-sizeThe "nothing found" message and the loading spinner.
--gog-autocomplete-clear-color / -clear-hover-color / -actions-insetClear button color and how far the trailing actions sit from the edge.
--gog-autocomplete-float-label-reserve / -in-top / -over-gap / -over-reserveFloat-label geometry, derived from the shared --gog-field-float-label-* scale.