Angular Autocomplete Component

Autocomplete

CoreUI PRO
This component is part of CoreUI PRO – a powerful UI library with over 250 components and 25+ templates, designed to help you build modern, responsive apps faster. Fully compatible with Angular, Bootstrap, React.js, and Vue.js.

Release candidate (RC)

This component is in the Release Candidate phase and its API is considered stable. Minor adjustments may still occur before the final release.

Develop robust Angular Autocomplete components that enable dynamic search, dropdown suggestions, and seamless integration with external data sources. The pinnacle Angular Autocomplete solution for contemporary web applications.

Available in Other JavaScript Frameworks

CoreUI Angular Autocomplete Component is also available for Bootstrap, React, and Vue. Explore framework-specific implementations below:

Added in v5.5.20

Overview

The CoreUI Angular Autocomplete Component is a powerful, feature-rich autocomplete solution that enhances form usability by providing intelligent suggestions based on user types. Whether you use static data, APIs, or complex search logic, this component delivers a smooth, accessible user experience with extensive customization options.

Key features of this Angular Autocomplete include:

  • Dynamic dropdown suggestions with real time filtering
  • External data integration with API support
  • Advanced search capabilities
  • Accessibility-first design
  • Custom styles
  • Customizable templates

Soon:

  • Performance optimization with virtual scrolling

Basic Example

This straightforward demonstration provides a clear guide on how to implement a basic autocomplete input field, emphasizing the essential attributes and configurations required for its functionality.

import { Component } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AutocompleteDirective, AutocompleteOption, FormLabelDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete',
  imports: [AutocompleteDirective, ReactiveFormsModule, FormLabelDirective],
  templateUrl: './autocomplete.component.html'
})
export class AutocompleteComponent {
  readonly options: AutocompleteOption[] = ['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js'];
}
<label cLabel for="ac-01">Framework</label>
<input
  [options]="options"
  [searchNoResultsLabel]="'No results found'"
  cAutocomplete
  cleaner
  highlightOptionsOnSearch
  indicator
  placeholder="Search technologies..."
  search="global"
  showHints
  type="text"
  value="Bootstrap"
  id="ac-01"
/>
<div class="form-text">Start typing to search option or provide value</div>

You can also use objects with option property for more structured data:

import { Component } from '@angular/core';
import { AutocompleteDirective, AutocompleteOption, FormLabelDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-2',
  imports: [AutocompleteDirective, FormLabelDirective],
  templateUrl: './autocomplete-2.component.html'
})
export class Autocomplete2Component {
  readonly options: AutocompleteOption[] = [
    {
      label: 'Angular',
      value: 1
    },
    {
      label: 'Bootstrap',
      value: 2
    },
    {
      label: 'Next.js',
      value: 3
    },
    {
      label: 'React.js',
      value: 4
    },
    {
      label: 'Vue.js',
      value: 5
    }
  ];
}
<label cLabel for="ac-02">Framework</label>
<input
  [options]="options"
  [searchNoResultsLabel]="'No results found'"
  cAutocomplete
  cleaner
  highlightOptionsOnSearch
  indicator
  placeholder="Search technologies..."
  search="global"
  showHints
  type="text"
  [value]="1"
  id="ac-02"
/>
<div class="form-text">Start typing to search option or provide value</div>

For a minimal implementation without additional features:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-3',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-3.component.html'
})
export class Autocomplete3Component {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
/>

Search functionality

Configure the search behavior to match your application’s needs. The search prop determines how the component handles user input and filtering.

By default, search operates only when the input field is focused and filters options internally:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-default-search',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-default-search.component.html'
})
export class AutocompleteDefaultSearchComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
/>

Enable global search functionality that allows users to start typing from anywhere within the component to begin searching:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-global-search',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-global-search.component.html'
})
export class AutocompleteGlobalSearchComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  search="global"
/>

When external search is enabled search="external", the component delegates search operations to your custom logic or external API. This is perfect for server-side filtering, complex search algorithms, or third-party search services:

html
<input cAutocomplete
       [options]="filteredOptions"
       (inputChange)="handleSearch($event)"
       search="external"
>

You can combine external search with global keyboard navigation:

html
<input cAutocomplete
       [options]="filteredOptions"
       (inputChange)="handleSearch($event)"
       [search]="{ external: true, global: true }"
>

See the External Data section for a complete working example.

Restricted selection

Limit users to only select from the provided options by enabling allowOnlyDefinedOptions. This prevents custom value entry:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-restricted-selection',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-restricted-selection.component.html'
})
export class AutocompleteRestrictedSelectionComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  allowOnlyDefinedOptions
  cAutocomplete
/>

UX enhancements

Enable intelligent hints and auto-completion features to improve user experience.

Show hints

Display intelligent completion hints that preview the first matching option as user types:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-show-hints',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-show-hints.component.html'
})
export class AutocompleteShowHintsComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  showHints
/>

Highlight matching text

Enhance search visibility by highlighting matching portions of option labels when user hovers over suggestions:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-highlight-matching-text',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-highlight-matching-text.component.html'
})
export class AutocompleteHighlightMatchingTextComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  highlightOptionsOnSearch
/>

Validation states

Apply validation styling to indicate input validity.

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-validation-states',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-validation-states.component.html',
  styleUrl: './autocomplete-validation-states.component.scss'
})
export class AutocompleteValidationStatesComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  [valid]="true"
  cAutocomplete
  placeholder="Valid autocomplete"
/>
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  [valid]="false"
  cAutocomplete
  placeholder="Invalid autocomplete"
/>
::ng-deep .autocomplete + .autocomplete {
  padding-top: .5rem;
}

Disabled state

Disable the component to prevent user interaction:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-disabled-state',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-disabled-state.component.html'
})
export class AutocompleteDisabledStateComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  disabled
  indicator
  placeholder="Disabled autocomplete..."
/>

Sizing

Choose from different sizes to match your design system and form layout:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-sizing',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-sizing.component.html',
  styleUrl: './autocomplete-sizing.component.scss'
})
export class AutocompleteSizingComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  placeholder="Large autocomplete..."
  sizing="lg"
/>
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  placeholder="Default autocomplete..."
/>
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  placeholder="Small autocomplete..."
  sizing="sm"
/>
::ng-deep .autocomplete + .autocomplete {
  padding-top: .5rem;
}

Cleaner functionality

Enable a cleaner button to quickly clear input element:

import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-cleaner-functionality',
  imports: [AutocompleteDirective],
  templateUrl: './autocomplete-cleaner-functionality.component.html'
})
export class AutocompleteCleanerFunctionalityComponent {}
<input
  [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
  cAutocomplete
  cleaner
  placeholder="With cleaner button..."
/>

Custom templates

The CoreUI Angular Autocomplete Component provides the flexibility to personalize options and group labels by utilizing custom templates. You can easily customize the options using the optionTemplate, and for groups, you can use optionGroupTemplate, as demonstrated in the examples below:

import { Component, signal } from '@angular/core';
import { AutocompleteDirective, ColComponent, FormLabelDirective, RowComponent } from '@coreui/angular';
import { IconDirective } from '@coreui/icons-angular';
import { cifDe, cifEs, cifGb, cifPl, cifUs } from '@coreui/icons';

@Component({
  selector: 'docs-autocomplete-custom-templates',
  imports: [AutocompleteDirective, ColComponent, FormLabelDirective, RowComponent, IconDirective],
  templateUrl: './autocomplete-custom-templates.component.html'
})
export class AutocompleteCustomTemplatesComponent {
  readonly flags: Record<string, string[]> = {
    de: cifDe,
    es: cifEs,
    gb: cifGb,
    pl: cifPl,
    us: cifUs
  };

  readonly cities = [
    {
      label: 'Germany',
      value: 'de',
      options: [
        {
          label: 'Saarbrücken'
        },
        {
          label: 'Berlin'
        },
        {
          label: 'München'
        }
      ]
    },
    {
      label: 'Spain',
      value: 'es',
      options: [
        {
          label: 'Madrid'
        },
        {
          label: 'Alicante'
        },
        {
          label: 'Huesca'
        }
      ]
    },
    {
      label: 'United Kingdom',
      value: 'gb',
      options: [
        {
          label: 'Liverpool'
        },
        {
          label: 'London'
        },
        {
          label: 'Manchester'
        }
      ]
    },
    {
      label: 'United States',
      value: 'us',
      options: [
        {
          label: 'Austin'
        },
        {
          label: 'Chicago'
        },
        {
          label: 'Los Angeles'
        }
      ]
    }
  ];

  readonly countries = this.cities.map(({ label, value }) => ({ label, value }));

  readonly filteredCities = signal(this.cities);

  handleOptionChange(country: any) {
    if (country === null) {
      this.filteredCities.set(this.cities);
      return;
    }
    const match = this.cities.find((c) => c.value === country?.value);
    this.filteredCities.set(match ? [match] : this.cities);
  }
}
<c-row>
  <c-col>
    <label cLabel for="ac-15-1">Country</label>
    <input (optionChange)="handleOptionChange($event)" [optionTemplate]="optionTpl" [options]="countries" cAutocomplete id="ac-15-1" placeholder="Select country" showHints />
  </c-col>
  <c-col>
    <label cLabel for="ac-15-2">City</label>
    <input [optionGroupTemplate]="groupTpl" [options]="filteredCities()" cAutocomplete id="ac-15-2" placeholder="Select city" showHints resetSelectionOnOptionsChange />
  </c-col>
</c-row>

<ng-template #optionTpl let-idx="idx" let-option>
  <div class="d-flex">
    <svg [cIcon]="flags[option.value]" class="me-3" size="xl"></svg>
    {{ option.label }}
  </div>
</ng-template>

<ng-template #groupTpl let-option>
  <div class="d-flex align-items-center">
    <svg [cIcon]="flags[option.value]" class="me-2" size="lg"></svg>
    {{ option.label }}
  </div>
</ng-template>

External Data

One of the most powerful features of the Angular Autocomplete component is its ability to work with external data sources, such as REST APIs, GraphQL endpoints, or server-side search services. This is essential when dealing with large datasets that shouldn’t be loaded entirely into the client.

Implementation example

Here’s how to implement external data loading with proper debouncing to optimize API calls:

import { JsonPipe } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http';
import { Component, computed, inject, signal } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import {
  AutocompleteDirective,
  AutocompleteOption,
  BadgeComponent,
  ButtonDirective,
  ColComponent,
  FormLabelDirective,
  RowComponent
} from '@coreui/angular';
import { UsersService } from './users.service';
import { distinctUntilChanged, map } from 'rxjs/operators';

@Component({
  selector: 'docs-autocomplete-implementation',
  imports: [
    AutocompleteDirective,
    BadgeComponent,
    FormLabelDirective,
    JsonPipe,
    ReactiveFormsModule,
    ButtonDirective,
    RowComponent,
    ColComponent
  ],
  templateUrl: './autocomplete-implementation.component.html'
})
export class AutocompleteImplementationComponent {
  readonly #usersService = inject(UsersService);

  protected formGroup = new FormGroup({
    userName: new FormControl<string>('Barbara')
  });

  readonly searchName = signal<string | undefined>(undefined);

  readonly usersResource = this.#usersService.getUsers(this.searchName);

  #users: AutocompleteOption[] = [];

  readonly users = computed(() => {
    const usersResource = this.usersResource;
    if (!usersResource.isLoading()) {
      const rawUsers = usersResource?.value()?.records?.map((user) => user.first_name as AutocompleteOption) ?? [];
      this.#users = [...new Set(rawUsers)];
    }
    return this.#users;
  });
  readonly error = computed(() => this.usersResource?.error() as HttpErrorResponse);
  readonly loading = computed(() => this.usersResource?.isLoading());

  // readonly #usersEffect = effect(() => {
  //   console.log('Users:', this.users());
  //   console.log('Loading:', this.loading());
  //   console.log('Error:', this.error());
  // });

  protected handleOptionChange($event: AutocompleteOption | null) {
    console.log('* handleOptionChange', $event);
  }

  protected handleValueChange($event: string | number | null | undefined) {
    console.log('* handleValueChange', $event);
  }

  protected handleInputChange($event: string) {
    console.log('* handleInputChange', $event);
    this.searchName.set($event);
  }

  protected changeValue() {
    const findName = 'Markus';
    this.searchName.set(findName);
    this.formGroup.get('userName')?.setValue(findName);
  }

  protected resetForm() {
    this.formGroup.reset();
  }

  constructor() {
    this.formGroup.valueChanges
      .pipe(
        map((value) => value.userName),
        distinctUntilChanged()
      )
      .subscribe((value) => {
        console.log('@ valueChange', value);
      });
  }
}
<form [formGroup]="formGroup">
  <c-row>
    <c-col>
      <label cLabel for="ac-16">Users
        <c-badge color="success" size="sm">{{ loading() ? 'loading' : '' }}</c-badge>
      </label>
      <input
        (inputChange)="handleInputChange($event)"
        (optionChange)="handleOptionChange($event)"
        (valueChange)="handleValueChange($event)"
        [delay]="500"
        [loading]="loading()"
        [options]="users()"
        [search]="{ external: true, global: true }"
        cAutocomplete
        cleaner
        formControlName="userName"
        highlightOptionsOnSearch
        id="ac-16"
        indicator
        placeholder="Search users..."
        showHints
      />
      <div class="form-text">Please select the user.</div>
      <hr>
      <button cButton (click)="changeValue()" class="me-1">Change</button>
      <button cButton (click)="resetForm()">Reset</button>
    </c-col>
    <c-col>
      <span> Form value: {{ formGroup.value | json }}</span>
    </c-col>
  </c-row>

  @if (error()) {
    @let message = error().error?.message || 'Unknown error';
    @let status = error().status;
    <div class="text-danger">An error {{ status }} occurred: {{ message }}</div>
  }
</form>
import { Injectable, Signal } from '@angular/core';
import { HttpParams, httpResource } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class UsersService {
  private usersUrl = 'https://apitest.coreui.io/demos/users';

  getUsers(userName: Signal<string | undefined>) {
    const apiParams: IApiParams = {
      limit: 1000,
      offset: 0,
      sort: 'first_name'
    };

    const httpParams: HttpParams = new HttpParams({ fromObject: { ...apiParams } });

    return httpResource<IUsersResponse>(() => ({
      url: `${this.usersUrl}?first_name=${userName() || undefined}`,
      params: httpParams
    }));
  }
}

export interface IUsersResponse {
  number_of_records: number;
  number_of_matching_records: number;
  records: IUser[];
}

export interface IUser {
  id: number;
  first_name: string;
  last_name: string;
  email: string;
  country: string;
  ip_address: string;
  registered: string;
}
export interface IApiParams {
  offset?: number;
  limit?: number;
  columnFilter?: string;
  columnSorter?: string;
  sort?: string;
}

Forms

Angular handles user input through reactive and template-driven forms. CoreUI Autocomplete supports both approaches.

Reactive

The Angular Autocomplete component can be used with reactive forms. You can bind the value to a form control using the formControlName directive.

import { JsonPipe } from '@angular/common';
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { distinctUntilChanged, map } from 'rxjs/operators';
import {
  AutocompleteDirective,
  ButtonDirective,
  ColComponent,
  IAutocompleteOption,
  RowComponent
} from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-reactive',
  imports: [AutocompleteDirective, ReactiveFormsModule, JsonPipe, ButtonDirective, ColComponent, RowComponent],
  templateUrl: './autocomplete-reactive.component.html'
})
export class AutocompleteReactiveComponent {
  readonly formGroup = new FormGroup({
    framework: new FormControl<string | null>('React.js', { nonNullable: true })
  });

  constructor() {
    this.formGroup.valueChanges
      .pipe(
        map((value) => value.framework),
        distinctUntilChanged()
      )
      .subscribe((value) => {
        console.log('* Value changed: ', value);
        console.log('* Control dirty: ', this.formGroup.get('framework')?.dirty);
        console.log('* Control pristine: ', this.formGroup.get('framework')?.pristine);
        console.log('* Control touched: ', this.formGroup.get('framework')?.touched);
      });
  }

  resetForm() {
    // console.log('Before reset - dirty:', this.formGroup.get('framework')?.dirty);
    // console.log('Before reset - pristine:', this.formGroup.get('framework')?.pristine);
    // console.log('Before reset - touched:', this.formGroup.get('framework')?.touched);
    this.formGroup.reset({ framework: '' });
    // console.log('After reset - dirty:', this.formGroup.get('framework')?.dirty);
    // console.log('After reset - pristine:', this.formGroup.get('framework')?.pristine);
    // console.log('After reset - touched:', this.formGroup.get('framework')?.touched);
  }

  protected changeValue() {
    this.formGroup.get('framework')?.setValue('Angular');
  }

  handleOptionChange($event: IAutocompleteOption | null) {
    console.log('* handleOptionChange: ', $event);
  }

  handleValueChange($event: string | number | null | undefined) {
    console.log('* handleValueChange: ', $event);
  }

  handleInputChange($event: any) {
    console.log('* handleInputChange: ', `*${$event}*`, typeof $event);
  }
}
<form [formGroup]="formGroup">
  <c-row>
    <c-col>
      <input
        (inputChange)="handleInputChange($event)"
        (optionChange)="handleOptionChange($event)"
        (valueChange)="handleValueChange($event)"
        [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
        cAutocomplete
        cleaner
        formControlName="framework"
        showHints
      />
    </c-col>
    <c-col>
      <span> Form value: {{ formGroup.value | json }}</span>
      <ul>
        <li> dirty: {{ formGroup.get('framework')?.dirty }}</li>
        <li> pristine: {{ formGroup.get('framework')?.pristine }}</li>
        <li> touched: {{ formGroup.get('framework')?.touched }}</li>
      </ul>
    </c-col>
  </c-row>
</form>
<br>
<button (click)="changeValue()" cButton class="me-1">Change</button>
<button (click)="resetForm()" cButton>Reset</button>

Template-driven

The Angular Autocomplete component can be used in template-driven forms. You can bind the value to a template variable using the ngModel directive.

import { JsonPipe } from '@angular/common';
import { Component, signal } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AutocompleteDirective, ColComponent, RowComponent } from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-template-driven',
  imports: [AutocompleteDirective, ReactiveFormsModule, JsonPipe, FormsModule, RowComponent, ColComponent],
  template: `
    <form #form="ngForm">
      <c-row>
        <c-col>
          <input
            [(ngModel)]="value"
            [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
            cAutocomplete
            cleaner
            name="templateCtrl"
          />
        </c-col>
        <c-col>
          <ul>
            <li>Form value: {{ form.value | json }}</li>
            <li>value: {{ value() }}</li>
          </ul>
        </c-col>
      </c-row>
    </form>
  `
})
export class AutocompleteTemplateDrivenComponent {
  readonly value = signal('Angular');
}

Signal forms

The Angular Autocomplete component works with signal forms. (preview)

import { JsonPipe } from '@angular/common';
import { Component, signal } from '@angular/core';
import { form, FormField, FormRoot, required } from '@angular/forms/signals';
import {
  AutocompleteDirective,
  ButtonDirective,
  ColComponent,
  FormFeedbackComponent,
  IAutocompleteOption,
  RowComponent
} from '@coreui/angular';

@Component({
  selector: 'docs-autocomplete-signal-forms',
  imports: [
    AutocompleteDirective,
    ButtonDirective,
    ColComponent,
    FormFeedbackComponent,
    FormField,
    FormRoot,
    RowComponent,
    JsonPipe
  ],
  template: `
    <form [formRoot]="frameworkForm">
      <c-row>
        <c-col>
          <label for="framework21">Framework:</label>
          @let ctrlState = frameworkForm.framework();
          <input
            (inputChange)="handleInputChange($event)"
            (optionChange)="handleOptionChange($event)"
            (valueChange)="handleValueChange($event)"
            [delay]="300"
            [formField]="frameworkForm.framework"
            [options]="frameworks"
            [valid]="
              ctrlState.touched() && ctrlState.invalid()
                ? false
                : ctrlState.touched() && !ctrlState.invalid()
                  ? true
                  : undefined
            "
            allowOnlyDefinedOptions
            cAutocomplete
            cleaner
            id="framework21"
            showHints
          />
          @if (ctrlState.touched() && ctrlState.invalid()) {
            @for (error of ctrlState.errors(); track error.kind) {
              @if (error.kind === 'required') {
                <c-form-feedback [valid]="false">
                  {{ error.message }}
                </c-form-feedback>
              }
            }
          }
          <div class="mt-3">
            <button type="button" cButton class="me-1" (click)="changeValue()">Change</button>
            <button type="reset" cButton class="me-1" (click)="resetForm()">Reset</button>
          </div>
        </c-col>
        <c-col>
          <strong>Control state: </strong>
          <ul>
            <li>Value: {{ frameworkForm.framework().value() | json }}</li>
            <li>Dirty: {{ frameworkForm.framework().dirty() }}</li>
            <li>Touched: {{ frameworkForm.framework().touched() }}</li>
            <li>Errors: {{ frameworkForm.framework().errors() | json }}</li>
          </ul>
        </c-col>
      </c-row>
    </form>
  `
})
export class AutocompleteSignalFormsComponent {
  readonly frameworkModel = signal({ framework: '' });

  readonly frameworkForm = form(this.frameworkModel, (schemaPath) => {
    required(schemaPath.framework, { message: 'framework is required' });
  });

  readonly frameworks = ['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js'];

  protected changeValue() {
    this.frameworkModel.set({ framework: 'Next.js' });
  }

  protected resetForm() {
    this.frameworkForm().reset({ framework: '' });
  }

  protected handleValueChange($event: number | string | undefined) {
    console.log('handleValueChange', $event);
  }

  protected handleOptionChange($event: IAutocompleteOption | null) {
    console.log('handleOptionChange', $event);
  }

  protected handleInputChange($event: string) {
    console.log('handleInputChange', $event);
  }
}

Accessibility

The Autocomplete component includes several accessibility features:

  • ARIA attributes: Proper role, aria-expanded, aria-haspopup, and aria-autocomplete attributes
  • Screen reader support: Descriptive labels and announcements for state changes
  • Keyboard navigation: Full keyboard support with arrow keys, Enter, Escape, and Tab
  • Focus management: Proper focus handling and visual focus indicators
  • Semantic markup: Uses appropriate HTML elements and structure

Keyboard shortcuts

KeyAction
Arrow DownNavigate to the next option or open dropdown
Arrow UpNavigate to the previous option
EnterSelect the highlighted option
EscapeClose the dropdown and clear focus
TabAccept hint completion (when hints are enabled)
Backspace DeleteClear input and trigger search

Customizing

CSS variables

Angular CoreUI Autocomplete use local CSS variables for easy customization. Values for the CSS variables are set via Sass, so Sass customization is still supported, too.

scss
.autocomplete {
  --cui-autocomplete-zindex: #{$autocomplete-zindex};
  --cui-autocomplete-font-family: #{$autocomplete-font-family};
  --cui-autocomplete-font-size: #{$autocomplete-font-size};
  --cui-autocomplete-font-weight: #{$autocomplete-font-weight};
  --cui-autocomplete-line-height: #{$autocomplete-line-height};
  --cui-autocomplete-color: #{$autocomplete-color};
  --cui-autocomplete-bg: #{$autocomplete-bg};
  --cui-autocomplete-box-shadow: #{$autocomplete-box-shadow};
  --cui-autocomplete-border-width: #{$autocomplete-border-width};
  --cui-autocomplete-border-color: #{$autocomplete-border-color};
  --cui-autocomplete-border-radius: #{$autocomplete-border-radius};
  --cui-autocomplete-disabled-color: #{$autocomplete-disabled-color};
  --cui-autocomplete-disabled-bg: #{$autocomplete-disabled-bg};
  --cui-autocomplete-disabled-border-color: #{$autocomplete-disabled-border-color};
  --cui-autocomplete-focus-color: #{$autocomplete-focus-color};
  --cui-autocomplete-focus-bg: #{$autocomplete-focus-bg};
  --cui-autocomplete-focus-border-color: #{$autocomplete-focus-border-color};
  --cui-autocomplete-focus-box-shadow: #{$autocomplete-focus-box-shadow};
  --cui-autocomplete-placeholder-color: #{$autocomplete-placeholder-color};
  --cui-autocomplete-padding-y: #{$autocomplete-padding-y};
  --cui-autocomplete-padding-x: #{$autocomplete-padding-x};
  --cui-autocomplete-cleaner-width: #{$autocomplete-cleaner-width};
  --cui-autocomplete-cleaner-height: #{$autocomplete-cleaner-height};
  --cui-autocomplete-cleaner-padding-y: #{$autocomplete-cleaner-padding-y};
  --cui-autocomplete-cleaner-padding-x: #{$autocomplete-cleaner-padding-x};
  --cui-autocomplete-cleaner-icon: #{escape-svg($autocomplete-cleaner-icon)};
  --cui-autocomplete-cleaner-icon-color: #{$autocomplete-cleaner-icon-color};
  --cui-autocomplete-cleaner-icon-hover-color: #{$autocomplete-cleaner-icon-hover-color};
  --cui-autocomplete-cleaner-icon-size: #{$autocomplete-cleaner-icon-size};
  --cui-autocomplete-indicator-width: #{$autocomplete-indicator-width};
  --cui-autocomplete-indicator-height: #{$autocomplete-indicator-height};
  --cui-autocomplete-indicator-padding-y: #{$autocomplete-indicator-padding-y};
  --cui-autocomplete-indicator-padding-x: #{$autocomplete-indicator-padding-x};
  --cui-autocomplete-indicator-icon: #{escape-svg($autocomplete-indicator-icon)};
  --cui-autocomplete-indicator-icon-color: #{$autocomplete-indicator-icon-color};
  --cui-autocomplete-indicator-icon-hover-color: #{$autocomplete-indicator-icon-hover-color};
  --cui-autocomplete-indicator-icon-size: #{$autocomplete-indicator-icon-size};
  --cui-autocomplete-dropdown-min-width: #{$autocomplete-dropdown-min-width};
  --cui-autocomplete-dropdown-bg: #{$autocomplete-dropdown-bg};
  --cui-autocomplete-dropdown-border-width: #{$autocomplete-dropdown-border-width};
  --cui-autocomplete-dropdown-border-color: #{$autocomplete-dropdown-border-color};
  --cui-autocomplete-dropdown-border-radius: #{$autocomplete-dropdown-border-radius};
  --cui-autocomplete-dropdown-box-shadow: #{$autocomplete-dropdown-box-shadow};
  --cui-autocomplete-options-padding-y: #{$autocomplete-options-padding-y};
  --cui-autocomplete-options-padding-x: #{$autocomplete-options-padding-x};
  --cui-autocomplete-options-font-size: #{$autocomplete-options-font-size};
  --cui-autocomplete-options-font-weight: #{$autocomplete-options-font-weight};
  --cui-autocomplete-options-color: #{$autocomplete-options-color};
  --cui-autocomplete-optgroup-label-padding-y: #{$autocomplete-optgroup-label-padding-y};
  --cui-autocomplete-optgroup-label-padding-x: #{$autocomplete-optgroup-label-padding-x};
  --cui-autocomplete-optgroup-label-font-size: #{$autocomplete-optgroup-label-font-size};
  --cui-autocomplete-optgroup-label-font-weight: #{$autocomplete-optgroup-label-font-weight};
  --cui-autocomplete-optgroup-label-color: #{$autocomplete-optgroup-label-color};
  --cui-autocomplete-optgroup-label-text-transform: #{$autocomplete-optgroup-label-text-transform};
  --cui-autocomplete-option-padding-y: #{$autocomplete-option-padding-y};
  --cui-autocomplete-option-padding-x: #{$autocomplete-option-padding-x};
  --cui-autocomplete-option-margin-y: #{$autocomplete-option-margin-y};
  --cui-autocomplete-option-margin-x: #{$autocomplete-option-margin-x};
  --cui-autocomplete-option-border-width: #{$autocomplete-option-border-width};
  --cui-autocomplete-option-border-color: #{$autocomplete-option-border-color};
  --cui-autocomplete-option-border-radius: #{$autocomplete-option-border-radius};
  --cui-autocomplete-option-box-shadow: #{$autocomplete-option-box-shadow};
  --cui-autocomplete-option-hover-color: #{$autocomplete-option-hover-color};
  --cui-autocomplete-option-hover-bg: #{$autocomplete-option-hover-bg};
  --cui-autocomplete-option-focus-box-shadow: #{$autocomplete-option-focus-box-shadow};
  --cui-autocomplete-option-disabled-color: #{$autocomplete-option-disabled-color};
  --cui-autocomplete-option-indicator-width: #{$autocomplete-option-indicator-width};
  --cui-autocomplete-option-indicator-bg: #{$autocomplete-option-indicator-bg};
  --cui-autocomplete-option-indicator-border: #{$autocomplete-option-indicator-border};
  --cui-autocomplete-option-indicator-border-radius: #{$autocomplete-option-indicator-border-radius};
  --cui-autocomplete-option-selected-bg: #{$autocomplete-option-selected-bg};
  --cui-autocomplete-option-selected-indicator-bg: #{$autocomplete-option-selected-indicator-bg};
  --cui-autocomplete-option-selected-indicator-bg-image: #{escape-svg($autocomplete-option-selected-indicator-bg-image)};
  --cui-autocomplete-option-selected-indicator-border-color: #{$autocomplete-option-selected-indicator-border-color};
}

SASS variables

scss
$autocomplete-zindex:                    1000 !default;
$autocomplete-font-family:               $input-font-family !default;
$autocomplete-font-size:                 $input-font-size !default;
$autocomplete-font-weight:               $input-font-weight !default;
$autocomplete-line-height:               $input-line-height !default;
$autocomplete-padding-y:                 $input-padding-y !default;
$autocomplete-padding-x:                 $input-padding-x !default;
$autocomplete-color:                     $input-color !default;
$autocomplete-bg:                        $input-bg !default;
$autocomplete-box-shadow:                $box-shadow-inset !default;

$autocomplete-border-width:              $input-border-width !default;
$autocomplete-border-color:              $input-border-color !default;
$autocomplete-border-radius:             $input-border-radius !default;
$autocomplete-border-radius-sm:          $input-border-radius-sm !default;
$autocomplete-border-radius-lg:          $input-border-radius-lg !default;

$autocomplete-disabled-color:            $input-disabled-color !default;
$autocomplete-disabled-bg:               $input-disabled-bg !default;
$autocomplete-disabled-border-color:     $input-disabled-border-color !default;

$autocomplete-focus-color:               $input-focus-color !default;
$autocomplete-focus-bg:                  $input-focus-bg !default;
$autocomplete-focus-border-color:        $input-focus-border-color !default;
$autocomplete-focus-box-shadow:          $input-btn-focus-box-shadow !default;

$autocomplete-placeholder-color:         var(--cui-secondary-color) !default;

$autocomplete-invalid-border-color:      $form-invalid-border-color !default;
$autocomplete-valid-border-color:        $form-valid-border-color !default;

$autocomplete-cleaner-width:             1.5rem !default;
$autocomplete-cleaner-height:            1.5rem !default;
$autocomplete-cleaner-padding-x:         0 !default;
$autocomplete-cleaner-padding-y:         0 !default;
$autocomplete-cleaner-icon:              url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#000'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>") !default;
$autocomplete-cleaner-icon-color:        var(--cui-tertiary-color) !default;
$autocomplete-cleaner-icon-hover-color:  var(--cui-body-color) !default;
$autocomplete-cleaner-icon-size:         .625rem !default;

$autocomplete-indicator-width:             1.5rem !default;
$autocomplete-indicator-height:            1.5rem !default;
$autocomplete-indicator-padding-x:         0 !default;
$autocomplete-indicator-padding-y:         0 !default;
$autocomplete-indicator-icon:              url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='#000'><path d='M256.045 416.136.717 160.807l29.579-29.579 225.749 225.748 225.749-225.748 29.579 29.579-255.328 255.329z'/></svg>") !default;
$autocomplete-indicator-icon-color:        var(--cui-tertiary-color) !default;
$autocomplete-indicator-icon-hover-color:  var(--cui-body-color) !default;
$autocomplete-indicator-icon-size:         .75rem !default;

$autocomplete-dropdown-min-width:        100% !default;
$autocomplete-dropdown-bg:               var(--cui-body-bg) !default;
$autocomplete-dropdown-border-color:     var(--cui-border-color) !default;
$autocomplete-dropdown-border-width:     var(--cui-border-width) !default;
$autocomplete-dropdown-border-radius:    var(--cui-border-radius) !default;
$autocomplete-dropdown-box-shadow:       var(--cui-box-shadow) !default;

$autocomplete-options-padding-y:         .5rem !default;
$autocomplete-options-padding-x:         .5rem !default;
$autocomplete-options-font-size:         $font-size-base !default;
$autocomplete-options-font-weight:       $font-weight-normal !default;
$autocomplete-options-color:             var(--cui-body-color) !default;

$autocomplete-optgroup-label-padding-y:       .5rem !default;
$autocomplete-optgroup-label-padding-x:       .625rem !default;
$autocomplete-optgroup-label-font-size:       80% !default;
$autocomplete-optgroup-label-font-weight:     $font-weight-bold !default;
$autocomplete-optgroup-label-color:           var(--cui-tertiary-color) !default;
$autocomplete-optgroup-label-text-transform:  uppercase !default;

$autocomplete-option-padding-y:               .5rem !default;
$autocomplete-option-padding-x:               .75rem !default;
$autocomplete-option-margin-y:                1px !default;
$autocomplete-option-margin-x:                0 !default;
$autocomplete-option-border-width:            $input-border-width !default;
$autocomplete-option-border-color:            transparent !default;
$autocomplete-option-border-radius:           var(--cui-border-radius) !default;
$autocomplete-option-box-shadow:              $box-shadow-inset !default;

$autocomplete-option-hover-color:             var(--cui-body-color) !default;
$autocomplete-option-hover-bg:                var(--cui-tertiary-bg) !default;

$autocomplete-option-focus-box-shadow:        $input-btn-focus-box-shadow !default;

$autocomplete-option-indicator-width:          1em !default;
$autocomplete-option-indicator-bg:             $form-check-input-bg !default;
$autocomplete-option-indicator-border:         $form-check-input-border !default;
$autocomplete-option-indicator-border-radius:  .25em !default;

$autocomplete-option-selected-bg:                      var(--cui-secondary-bg) !default;
$autocomplete-option-selected-indicator-bg:            $form-check-input-checked-bg-color !default;
$autocomplete-option-selected-indicator-bg-image:      $form-check-input-checked-bg-image !default;
$autocomplete-option-selected-indicator-border-color:  $autocomplete-option-selected-indicator-bg !default;

$autocomplete-option-disabled-color:        var(--cui-secondary-color) !default;

$autocomplete-font-size-lg:                 $input-font-size-lg !default;
$autocomplete-padding-y-lg:                 $input-padding-y-lg !default;
$autocomplete-padding-x-lg:                 $input-padding-x-lg !default;

$autocomplete-font-size-sm:                 $input-font-size-sm !default;
$autocomplete-padding-y-sm:                 $input-padding-y-sm !default;
$autocomplete-padding-x-sm:                 $input-padding-x-sm !default;

API reference

Autocomplete Module

ts
import { NgModule } from '@angular/core';
import { AutocompleteModule } from '@coreui/angular';

@NgModule({
  imports: [AutocompleteModule]
})
export class CustomAppModule {}

Autocomplete Standalone

ts
import { Component } from '@angular/core';
import { AutocompleteDirective } from '@coreui/angular';

@Component({
  template: ` <input [options]="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']" cAutocomplete /> `,
  imports: [AutocompleteDirective],
  standalone: true
})
export class CustomAppComponent {}

cAutocomplete

directive


Inputs
namedescriptiontypedefault
allowOnlyDefinedOptionsOnly allow selection of predefined options. When true, users cannot enter custom values that are not in the options list. When false, users can enter and select custom values.booleanfalse
cleanerEnables selection cleaner element. When true, displays a clear button that allows users to reset the selection. The cleaner button is only shown when there is a selection and the component is not disabled or read-only.booleanfalse
clearSearchOnSelectWhether to clear the internal search state after selecting an option. When set to true, the internal search value used for filtering options is cleared after a selection is made. This affects only the component’s internal logic. Note: This does not clear the visible input field if the component is using external search or is controlled via the searchValue prop. In such cases, clearing must be handled externally.booleantrue
disabledToggle the disabled state for the component. When true, the Angular autocomplete is non-interactive and appears visually disabled. Users cannot type, select options, or trigger the dropdown.booleanundefined
highlightOptionsOnSearchHighlight options that match the search criteria. When true, matching portions of option labels are visually highlighted based on the current search input value.booleanfalse
indicatorShow dropdown indicator/arrow button. When true, displays a dropdown arrow button that can be clicked to manually show or hide the options dropdown.booleanfalse
loadingWhen set, the options list will have a loading style: loading spinner and reduced opacity. Use this to indicate that options are being fetched asynchronously. The dropdown remains functional but shows visual loading indicators.booleanfalse
optionsList of option elements. Can contain Option objects, OptionsGroup objects, or plain strings. Plain strings are converted to simple Option objects internally. This is a required prop - the Angular Autocomplete needs options to function.AutocompleteOption[][]
optionsMaxHeightSets maxHeight of options list. Controls the maximum height of the dropdown options container. Can be a number (pixels) or a CSS length string (e.g., ‘200px’, ‘10rem’). When content exceeds this height, a scrollbar will appear.string | numberauto
optionGroupTemplateCustom template for rendering option groups. Allows customization of how option group headers appear in the dropdown.TemplateRefundefined
optionTemplateCustom template for rendering individual options. Allows complete customization of how each option appears in the dropdown.TemplateRefundefined
placeholderSpecifies a short hint that is visible in the search input. Displayed when the input is empty to guide user interaction. Standard HTML input placeholder behavior.stringundefined
readOnlyToggle the readonly state for the component. When true, users can view and interact with the dropdown but cannot type in the search input or modify the selection through typing. Selection via clicking options may still be possible.booleanfalse
resetSelectionOnOptionsChangeDetermines whether the selected options should be cleared when the options list is updated. When true, any previously selected options will be reset whenever the options list undergoes a change. This ensures that outdated selections are not retained when new options are provided.booleanfalse
searchEnables and configures search functionality.
{ global: boolean, external: boolean }
'global' | 'external' undefined
searchNoResultsLabelSets the label for no results when filtering - false: Don’t show any message when no results found, true: Show default No results found message, string: Show custom text messagestring | booleanundefined
showHintsShow hint options based on the current input value. When true, displays a preview/hint of the first matching option as semi-transparent text in the input field, similar to browser autocomplete.booleanfalse
sizingSize the component small, large, or default.sm | lgundefined
validSet component validation state.boolean | undefinedundefined
valueSets the initially selected value for the Angular Autocomplete component. Can be a string (matched against option labels) or number (matched against option values). The component will attempt to find and select the matching option on mount.string | number
visibleToggle the visibility of autocomplete dropdown. Controls whether the dropdown is initially visible. The dropdown visibility can still be toggled through user interaction.booleanfalse

jsx
import { AutocompleteDirective } from '@coreui/angular-pro'

Props

PropertyDefaultType
allowOnlyDefinedOptionsfalseboolean

Only allow selection of predefined options. When true, users cannot enter custom values that are not in the options list. When false, users can enter and select custom values.

ariaCleanerLabel5.7.7+'Clear selection'string

Sets the accessible label (aria-label) for the button that clears the current selection. This improves accessibility for screen readers.

ariaIndicatorLabel5.7.7+'Toggle visibility of options menu'string

Sets the accessible label (aria-label) for the dropdown toggle indicator button. This improves accessibility for screen readers.

cleanerfalseboolean

Enables selection cleaner element. When true, displays a clear button that allows users to reset the selection. The cleaner button is only shown when there is a selection and the component is not disabled or read-only.

clearSearchOnSelecttrueboolean

Whether to clear the internal search state after selecting an option. When set to true, the internal search value used for filtering options is cleared after a selection is made. This affects only the component's internal logic. Note: This does **not** clear the visible input field if the component is using external search or is controlled via the searchValue prop. In such cases, clearing must be handled externally.

delay150number

Debounce delay in milliseconds for filtering options based on search input. Controls how quickly the options list updates as the user types. Higher values reduce update frequency for better performance with large datasets.

disabledfalseboolean

Toggle the disabled state for the component. When true, the Angular autocomplete is non-interactive and appears visually disabled. Users cannot type, select options, or trigger the dropdown.

Highlight options that match the search criteria. When true, matching portions of option labels are visually highlighted based on the current search input value.

id'autocomplete-<nextId>'string

Unique identifier for the Autocomplete component. If not provided, a default ID will be generated.

indicatorfalseboolean

Show dropdown indicator/arrow button. When true, displays a dropdown arrow button that can be clicked to manually show or hide options dropdown.

itemSize40number

The size of the option item in the list (in pixels).

loadingfalseboolean

When set, the options list will have a loading style: loading spinner and reduced opacity. Use this to indicate that options are being fetched asynchronously. The dropdown remains functional but shows visual loading indicators.

optionGroupTemplate-TemplateRef<any>

Custom template for rendering option groups. Allows customization of how option group headers appear in the dropdown.

options-AutocompleteOption[]

List of option elements. Can contain Option objects, OptionsGroup objects, or plain strings. Plain strings are converted to simple Option objects internally. This is a required prop - the Angular autocomplete needs options to function.

optionsMaxHeight'auto'string, number

Sets maxHeight of options list. Controls the maximum height of the dropdown options container. Can be a number (pixels) or a CSS length string (e.g., '200px', '10rem'). When content exceeds this height, a scrollbar will appear.

optionTemplate-TemplateRef<any>

Custom template for rendering individual options. Allows complete customization of how each option appears in the dropdown.

placeholder-string

Specifies a short hint that is visible in the search input. Displayed when the input is empty to guide user interaction. Standard HTML input placeholder behavior.

popperOptionsdefaultPopperOptionsPartial<Options>

Optional popper Options object

readOnlyfalseboolean

Toggle the readonly state for the component. When true, users can view and interact with the dropdown but cannot type in the search input or modify the selection through typing. Selection via clicking options may still be possible.

resetSelectionOnOptionsChangefalseboolean

Determines whether the selected options should be cleared when the options list is updated. When true, any previously selected options will be reset whenever the options list undergoes a change. This ensures that outdated selections are not retained when new options are provided.

Enables and configures search functionality. - 'external': Search is handled externally, filtering is not applied internally - 'global': Enables global keyboard search when dropdown is closed - Object with external and global boolean properties for fine-grained control

searchNoResultsLabelfalsestring, boolean, TemplateRef<any>

Sets the label for no results when filtering. - false: Don't show any message when no results found - true: Show default "No results found" message - string: Show custom text message - TemplateRef: Show custom component/element

showHintsfalseboolean

Show hint options based on the current input value. When true, displays a preview/hint of the first matching option as semi-transparent text in the input field, similar to browser autocomplete.

sizing-'', 'sm', 'lg'

Size the component small or large. - 'sm': Small size variant - 'lg': Large size variant - undefined: Default/medium size

validundefinedboolean

Set form input validation state to valid.

valueundefinedstring, number

Sets the initially selected value for the Angular autocomplete component. Can be a string (matched against option labels) or number (matched against option values). The component will attempt to find and select the matching option on mount.

virtualScrollerfalseboolean

Enable virtual scroller for the options list. When true, only visible options are rendered in the DOM for better performance with large option lists. Works in conjunction with visibleItems prop.

visiblefalseboolean

Toggle the visibility of autocomplete dropdown. Controls whether the dropdown is initially visible. The dropdown visibility can still be toggled through user interaction.

visibleItems8number

Amount of visible items when virtualScroller is enabled. Determines how many option items are rendered at once when virtual scrolling is active. Higher values show more items but use more memory. Lower values improve performance.

Events

Event name
inputChange

Emits an event when the filter/search value changes. Called whenever the user types in the search input. Useful for implementing external search functionality or analytics.

  • $event string
optionChange

Emits an event when a user changes the selected option. Called with the selected option object or undefined when cleared. This is the primary callback for handling selection changes.

  • $event IAutocompleteOption | null
valueChange

Event emitted on value change.

  • $event string | null
visibleChange

The callback is fired when the dropdown requests to be hidden. Called when the dropdown closes due to user interaction, clicks outside, escape key, or programmatic changes.

  • $event boolean