combobox

Autocomplete input with a list of suggestions.

PreviousNext
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardComboboxImports } from '../combobox.imports';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-preview',
  imports: [ZardComboboxImports],
  template: `
    <z-combobox [(zValue)]="value">
      <z-combobox-input placeholder="Select a framework" />

      <z-combobox-content>
        <z-combobox-empty>No items found.</z-combobox-empty>

        <z-combobox-list>
          @for (framework of frameworks; track framework.value) {
            <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxPreviewComponent {
  readonly value = signal<string | string[] | null>(null);

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'ember', label: 'Ember.js' },
    { value: 'nextjs', label: 'Next.js' },
  ];
}

Installation

Copy
npx zard-cli@latest add combobox

Usage

import { ZardComboboxImports } from '@/shared/components/combobox/combobox.imports';
Copy
<z-combobox [(zValue)]="value">
  <z-combobox-input placeholder="Search framework..." />

  <z-combobox-content>
    <z-combobox-empty>No framework found.</z-combobox-empty>

    <z-combobox-list>
      @for (framework of frameworks; track framework.value) {
        <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
      }
    </z-combobox-list>
  </z-combobox-content>
</z-combobox>
Copy

Examples

multiple

zMultiple turns the combobox into a multi-select. Selected values render as removable z-combobox-chips inside z-combobox-chips, backed by an input[z-combobox-chips-input] that also opens the popup on focus; the popup stays open after each pick. Paired here with zAutoHighlight so Enter selects the top match without an extra arrow key press.
Angular
import { Component, computed, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardComboboxImports } from '../combobox.imports';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-multiple',
  imports: [ZardComboboxImports],
  template: `
    <z-combobox zMultiple zAutoHighlight zWidth="full" [(zValue)]="value">
      <z-combobox-chips class="w-full max-w-xs">
        @for (selected of selectedValues(); track selected) {
          <z-combobox-chip [zValue]="selected">{{ labelOf(selected) }}</z-combobox-chip>
        }

        <input z-combobox-chips-input placeholder="Add framework" />
      </z-combobox-chips>

      <z-combobox-content>
        <z-combobox-empty>No items found.</z-combobox-empty>

        <z-combobox-list>
          @for (framework of frameworks; track framework.value) {
            <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxMultipleComponent {
  readonly value = signal<string | string[] | null>(['angular']);

  readonly selectedValues = computed(() => {
    const value = this.value();
    return Array.isArray(value) ? value : value ? [value] : [];
  });

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'ember', label: 'Ember.js' },
    { value: 'nextjs', label: 'Next.js' },
  ];

  labelOf(value: string): string {
    return this.frameworks.find(framework => framework.value === value)?.label ?? value;
  }
}

clear

zShowClear on z-combobox-input adds a button[z-combobox-clear] next to the chevron once a value is selected. It clears the selection and the query and returns focus to the input.
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardComboboxImports } from '../combobox.imports';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-clear',
  imports: [ZardComboboxImports],
  template: `
    <z-combobox [(zValue)]="value">
      <z-combobox-input zShowClear placeholder="Select a framework" />

      <z-combobox-content>
        <z-combobox-empty>No items found.</z-combobox-empty>

        <z-combobox-list>
          @for (framework of frameworks; track framework.value) {
            <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxClearComponent {
  readonly value = signal<string | string[] | null>('angular');

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'ember', label: 'Ember.js' },
    { value: 'nextjs', label: 'Next.js' },
  ];
}

groups

Options organised into named sections with z-combobox-group and z-combobox-label, divided by z-combobox-separator. A group hides itself automatically once every item inside it is filtered out by the query.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';

import { ZardComboboxImports } from '../combobox.imports';

@Component({
  selector: 'z-demo-combobox-groups',
  imports: [ZardComboboxImports],
  template: `
    <z-combobox zWidth="md" [(zValue)]="value">
      <z-combobox-input placeholder="Select a timezone" />

      <z-combobox-content>
        <z-combobox-empty>No timezones found.</z-combobox-empty>

        <z-combobox-list>
          @for (group of timezones; track group.label; let last = $last) {
            <z-combobox-group>
              <z-combobox-label>{{ group.label }}</z-combobox-label>

              @for (zone of group.options; track zone) {
                <z-combobox-item [zValue]="zone">{{ zone }}</z-combobox-item>
              }

              @if (!last) {
                <z-combobox-separator />
              }
            </z-combobox-group>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxGroupsComponent {
  readonly value = signal<string | string[] | null>(null);

  readonly timezones = [
    {
      label: 'Americas',
      options: [
        '(GMT-5) New York',
        '(GMT-8) Los Angeles',
        '(GMT-6) Chicago',
        '(GMT-5) Toronto',
        '(GMT-8) Vancouver',
        '(GMT-3) São Paulo',
      ],
    },
    {
      label: 'Europe',
      options: [
        '(GMT+0) London',
        '(GMT+1) Paris',
        '(GMT+1) Berlin',
        '(GMT+1) Rome',
        '(GMT+1) Madrid',
        '(GMT+1) Amsterdam',
      ],
    },
    {
      label: 'Asia/Pacific',
      options: [
        '(GMT+9) Tokyo',
        '(GMT+8) Shanghai',
        '(GMT+8) Singapore',
        '(GMT+4) Dubai',
        '(GMT+11) Sydney',
        '(GMT+9) Seoul',
      ],
    },
  ];
}

custom items

A z-combobox-item can project arbitrary content instead of plain text — here each item renders a z-item with a title and description. zLabel keeps driving the filter match and the closed-state text independently of the projected markup.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';

import { ZardItemImports } from '../../item/item.imports';
import { ZardComboboxImports } from '../combobox.imports';

@Component({
  selector: 'z-demo-combobox-custom-items',
  imports: [ZardComboboxImports, ZardItemImports],
  template: `
    <z-combobox zWidth="md" [(zValue)]="value">
      <z-combobox-input placeholder="Search countries..." />

      <z-combobox-content>
        <z-combobox-empty>No countries found.</z-combobox-empty>

        <z-combobox-list>
          @for (country of countries; track country.code) {
            <z-combobox-item [zValue]="country.value" [zLabel]="country.label">
              <div z-item zSize="xs" class="p-0">
                <div z-item-content>
                  <div z-item-title class="whitespace-nowrap">{{ country.label }}</div>
                  <p z-item-description>{{ country.continent }} ({{ country.code }})</p>
                </div>
              </div>
            </z-combobox-item>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxCustomItemsComponent {
  readonly value = signal<string | string[] | null>(null);

  readonly countries = [
    { code: 'ar', value: 'argentina', label: 'Argentina', continent: 'South America' },
    { code: 'au', value: 'australia', label: 'Australia', continent: 'Oceania' },
    { code: 'br', value: 'brazil', label: 'Brazil', continent: 'South America' },
    { code: 'ca', value: 'canada', label: 'Canada', continent: 'North America' },
    { code: 'cn', value: 'china', label: 'China', continent: 'Asia' },
    { code: 'co', value: 'colombia', label: 'Colombia', continent: 'South America' },
    { code: 'eg', value: 'egypt', label: 'Egypt', continent: 'Africa' },
    { code: 'fr', value: 'france', label: 'France', continent: 'Europe' },
    { code: 'de', value: 'germany', label: 'Germany', continent: 'Europe' },
    { code: 'it', value: 'italy', label: 'Italy', continent: 'Europe' },
    { code: 'jp', value: 'japan', label: 'Japan', continent: 'Asia' },
    { code: 'ke', value: 'kenya', label: 'Kenya', continent: 'Africa' },
    { code: 'mx', value: 'mexico', label: 'Mexico', continent: 'North America' },
    { code: 'nz', value: 'new-zealand', label: 'New Zealand', continent: 'Oceania' },
    { code: 'ng', value: 'nigeria', label: 'Nigeria', continent: 'Africa' },
    { code: 'za', value: 'south-africa', label: 'South Africa', continent: 'Africa' },
    { code: 'kr', value: 'south-korea', label: 'South Korea', continent: 'Asia' },
    { code: 'gb', value: 'united-kingdom', label: 'United Kingdom', continent: 'Europe' },
    { code: 'us', value: 'united-states', label: 'United States', continent: 'North America' },
  ];
}

invalid

zInvalid on z-combobox marks it invalid, setting data-invalid on the host and aria-invalid on the input. Composed here inside z-field with z-field-label and z-field-error for the full validation pattern.
Please select a framework.
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardFieldImports } from '../../field/field.imports';
import { ZardComboboxImports } from '../combobox.imports';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-invalid',
  imports: [ZardComboboxImports, ZardFieldImports],
  template: `
    <div z-field class="w-full min-w-48" data-invalid="true">
      <label z-field-label [for]="combobox.inputId">Framework</label>

      <z-combobox #combobox="zCombobox" zInvalid [(zValue)]="value">
        <z-combobox-input placeholder="Select a framework" />

        <z-combobox-content>
          <z-combobox-empty>No items found.</z-combobox-empty>

          <z-combobox-list>
            @for (framework of frameworks; track framework.value) {
              <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
            }
          </z-combobox-list>
        </z-combobox-content>
      </z-combobox>

      <z-field-error>Please select a framework.</z-field-error>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxInvalidComponent {
  readonly value = signal<string | string[] | null>(null);

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'ember', label: 'Ember.js' },
    { value: 'nextjs', label: 'Next.js' },
  ];
}

disabled

zDisabled on z-combobox disables the whole control; zDisabled on an individual z-combobox-item disables just that option while leaving the rest selectable.
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardComboboxImports } from '../combobox.imports';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-disabled',
  imports: [ZardComboboxImports],
  template: `
    <div class="flex flex-wrap gap-4">
      <z-combobox zDisabled>
        <z-combobox-input placeholder="Select a framework" />

        <z-combobox-content>
          <z-combobox-empty>No items found.</z-combobox-empty>

          <z-combobox-list>
            @for (framework of frameworks; track framework.value) {
              <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
            }
          </z-combobox-list>
        </z-combobox-content>
      </z-combobox>

      <z-combobox [(zValue)]="value">
        <z-combobox-input placeholder="Select a framework" />

        <z-combobox-content>
          <z-combobox-empty>No items found.</z-combobox-empty>

          <z-combobox-list>
            @for (framework of frameworksWithDisabled; track framework.value) {
              <z-combobox-item [zValue]="framework.value" [zDisabled]="framework.disabled ?? false">
                {{ framework.label }}
              </z-combobox-item>
            }
          </z-combobox-list>
        </z-combobox-content>
      </z-combobox>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxDisabledComponent {
  readonly value = signal<string | string[] | null>(null);

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
  ];

  frameworksWithDisabled: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React', disabled: true },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte', disabled: true },
    { value: 'ember', label: 'Ember.js' },
  ];
}

auto highlight

zAutoHighlight highlights the first matching, selectable item as soon as the query changes, so pressing Enter selects it without navigating with the arrow keys first. Compare with popup, where the popup itself — not the highlight — is the thing being customised.
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardComboboxImports } from '../combobox.imports';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-auto-highlight',
  imports: [ZardComboboxImports],
  template: `
    <z-combobox zAutoHighlight [(zValue)]="value">
      <z-combobox-input placeholder="Select a framework" />

      <z-combobox-content>
        <z-combobox-empty>No items found.</z-combobox-empty>

        <z-combobox-list>
          @for (framework of frameworks; track framework.value) {
            <z-combobox-item [zValue]="framework.value">{{ framework.label }}</z-combobox-item>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxAutoHighlightComponent {
  readonly value = signal<string | string[] | null>(null);

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'ember', label: 'Ember.js' },
    { value: 'nextjs', label: 'Next.js' },
  ];
}

shorthand

zard-only shorthand: pass [options] (or [groups]) straight to z-combobox and project nothing. With no z-combobox-content in the template, the root renders its own input and popup from the option list — no z-combobox-input, z-combobox-item or z-combobox-content markup needed. (zComboSelected) reports the option that was chosen. Trades the composition every other example uses for brevity.

Selected: none

import { Component, signal, ChangeDetectionStrategy } from '@angular/core';

import { ZardComboboxComponent } from '../combobox.component';
import type { ZardComboboxOption } from '../combobox.types';

@Component({
  selector: 'z-demo-combobox-shorthand',
  imports: [ZardComboboxComponent],
  template: `
    <div class="flex flex-col gap-2">
      <z-combobox
        [options]="frameworks"
        placeholder="Select framework..."
        searchPlaceholder="Search framework..."
        emptyText="No framework found."
        (zComboSelected)="selected.set($event)"
      />

      <p class="text-muted-foreground text-sm">Selected: {{ selected()?.label ?? 'none' }}</p>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxShorthandComponent {
  readonly selected = signal<ZardComboboxOption | null>(null);

  frameworks: ZardComboboxOption[] = [
    { value: 'angular', label: 'Angular' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue.js' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'ember', label: 'Ember.js' },
    { value: 'nextjs', label: 'Next.js' },
  ];
}

popup

A standalone button[z-button][z-combobox-trigger] opens and anchors the popup, with z-combobox-value rendering the selected label inside it. The z-combobox-input moves inside z-combobox-content with [zShowTrigger]="false", so typing only happens once the popup is open — unlike preview, where the input is always visible and drives the popup directly.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';

import { ZardButtonComponent } from '../../button/button.component';
import { ZardComboboxImports } from '../combobox.imports';

@Component({
  selector: 'z-demo-combobox-popup',
  imports: [ZardButtonComponent, ZardComboboxImports],
  template: `
    <z-combobox zWidth="full" class="w-fit" [(zValue)]="value">
      <button type="button" z-button z-combobox-trigger zType="outline" class="w-64 justify-between font-normal">
        <z-combobox-value placeholder="Select country" />
      </button>

      <z-combobox-content>
        <z-combobox-input [zShowTrigger]="false" placeholder="Search" />

        <z-combobox-empty>No items found.</z-combobox-empty>

        <z-combobox-list>
          @for (country of countries; track country.code) {
            <z-combobox-item [zValue]="country.value" [zLabel]="country.label">{{ country.label }}</z-combobox-item>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxPopupComponent {
  readonly value = signal<string | string[] | null>(null);

  readonly countries = [
    { code: 'ar', value: 'argentina', label: 'Argentina', continent: 'South America' },
    { code: 'au', value: 'australia', label: 'Australia', continent: 'Oceania' },
    { code: 'br', value: 'brazil', label: 'Brazil', continent: 'South America' },
    { code: 'ca', value: 'canada', label: 'Canada', continent: 'North America' },
    { code: 'cn', value: 'china', label: 'China', continent: 'Asia' },
    { code: 'co', value: 'colombia', label: 'Colombia', continent: 'South America' },
    { code: 'eg', value: 'egypt', label: 'Egypt', continent: 'Africa' },
    { code: 'fr', value: 'france', label: 'France', continent: 'Europe' },
    { code: 'de', value: 'germany', label: 'Germany', continent: 'Europe' },
    { code: 'it', value: 'italy', label: 'Italy', continent: 'Europe' },
    { code: 'jp', value: 'japan', label: 'Japan', continent: 'Asia' },
    { code: 'ke', value: 'kenya', label: 'Kenya', continent: 'Africa' },
    { code: 'mx', value: 'mexico', label: 'Mexico', continent: 'North America' },
    { code: 'nz', value: 'new-zealand', label: 'New Zealand', continent: 'Oceania' },
    { code: 'ng', value: 'nigeria', label: 'Nigeria', continent: 'Africa' },
    { code: 'za', value: 'south-africa', label: 'South Africa', continent: 'Africa' },
    { code: 'kr', value: 'south-korea', label: 'South Korea', continent: 'Asia' },
    { code: 'gb', value: 'united-kingdom', label: 'United Kingdom', continent: 'Europe' },
    { code: 'us', value: 'united-states', label: 'United States', continent: 'North America' },
  ];
}

input group

A z-input-group-addon projected into z-combobox-input adds a leading icon to the real z-input-group the input renders internally, shown together with grouped options.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideGlobe } from '@ng-icons/lucide';

import { ZardInputGroupAddonComponent } from '../../input-group/input-group.component';
import { ZardComboboxImports } from '../combobox.imports';

@Component({
  selector: 'z-demo-combobox-input-group',
  imports: [NgIcon, ZardComboboxImports, ZardInputGroupAddonComponent],
  template: `
    <z-combobox zWidth="md" [(zValue)]="value">
      <z-combobox-input placeholder="Select a timezone">
        <z-input-group-addon>
          <ng-icon name="lucideGlobe" />
        </z-input-group-addon>
      </z-combobox-input>

      <z-combobox-content>
        <z-combobox-empty>No timezones found.</z-combobox-empty>

        <z-combobox-list>
          @for (group of timezones; track group.label) {
            <z-combobox-group>
              <z-combobox-label>{{ group.label }}</z-combobox-label>

              @for (zone of group.options; track zone) {
                <z-combobox-item [zValue]="zone">{{ zone }}</z-combobox-item>
              }
            </z-combobox-group>
          }
        </z-combobox-list>
      </z-combobox-content>
    </z-combobox>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideGlobe })],
})
export class ZardDemoComboboxInputGroupComponent {
  readonly value = signal<string | string[] | null>(null);

  readonly timezones = [
    {
      label: 'Americas',
      options: [
        '(GMT-5) New York',
        '(GMT-8) Los Angeles',
        '(GMT-6) Chicago',
        '(GMT-5) Toronto',
        '(GMT-8) Vancouver',
        '(GMT-3) São Paulo',
      ],
    },
    {
      label: 'Europe',
      options: [
        '(GMT+0) London',
        '(GMT+1) Paris',
        '(GMT+1) Berlin',
        '(GMT+1) Rome',
        '(GMT+1) Madrid',
        '(GMT+1) Amsterdam',
      ],
    },
    {
      label: 'Asia/Pacific',
      options: [
        '(GMT+9) Tokyo',
        '(GMT+8) Shanghai',
        '(GMT+8) Singapore',
        '(GMT+4) Dubai',
        '(GMT+11) Sydney',
        '(GMT+9) Seoul',
      ],
    },
  ];
}

rtl

To enable RTL support in zard/ui, see the RTL configuration guide.
الفئاتالتكنولوجيا
// You will notice this example is rendered inside a wrapper that sets the dir and data-lang attributes, and
// reads its text from a translations helper. This is because this site is not RTL by default.
// In your application you won't need either: set dir="rtl" on <html> (or use the CDK Dir directive on a subtree)
// and write the text of your own language. See the RTL guide: https://zardui.com/docs/rtl

import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';

import { ZardComboboxImports } from '@/shared/components/combobox/combobox.imports';
import { injectRtlTranslation, type ZardRtlTranslations } from '@/shared/demo-utils/rtl-translation';

const categories = ['technology', 'design', 'business', 'marketing', 'education', 'health'] as const;

interface ComboboxRtlValues {
  label: string;
  placeholder: string;
  empty: string;
  technology: string;
  design: string;
  business: string;
  marketing: string;
  education: string;
  health: string;
}

const translations: ZardRtlTranslations<ComboboxRtlValues> = {
  en: {
    dir: 'ltr',
    values: {
      label: 'Categories',
      placeholder: 'Add categories',
      empty: 'No categories found.',
      technology: 'Technology',
      design: 'Design',
      business: 'Business',
      marketing: 'Marketing',
      education: 'Education',
      health: 'Health',
    },
  },
  ar: {
    dir: 'rtl',
    values: {
      label: 'الفئات',
      placeholder: 'أضف فئات',
      empty: 'لم يتم العثور على فئات.',
      technology: 'التكنولوجيا',
      design: 'التصميم',
      business: 'الأعمال',
      marketing: 'التسويق',
      education: 'التعليم',
      health: 'الصحة',
    },
  },
  he: {
    dir: 'rtl',
    values: {
      label: 'קטגוריות',
      placeholder: 'הוסף קטגוריות',
      empty: 'לא נמצאו קטגוריות.',
      technology: 'טכנולוגיה',
      design: 'עיצוב',
      business: 'עסקים',
      marketing: 'שיווק',
      education: 'חינוך',
      health: 'בריאות',
    },
  },
};

@Component({
  selector: 'z-demo-combobox-rtl',
  imports: [ZardComboboxImports],
  template: `
    <div class="mx-auto grid w-full max-w-xs gap-2">
      <span class="text-sm font-medium">{{ i18n.t().label }}</span>

      <z-combobox zMultiple zAutoHighlight zWidth="full" [(zValue)]="value">
        <z-combobox-chips class="w-full">
          @for (selected of selectedValues(); track selected) {
            <z-combobox-chip [zValue]="selected">{{ i18n.t()[selected] }}</z-combobox-chip>
          }

          <input z-combobox-chips-input [placeholder]="i18n.t().placeholder" />
        </z-combobox-chips>

        <z-combobox-content>
          <z-combobox-empty>{{ i18n.t().empty }}</z-combobox-empty>

          <z-combobox-list>
            @for (category of categories; track category) {
              <z-combobox-item [zValue]="category">{{ i18n.t()[category] }}</z-combobox-item>
            }
          </z-combobox-list>
        </z-combobox-content>
      </z-combobox>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoComboboxRtlComponent {
  protected readonly i18n = injectRtlTranslation(translations);

  protected readonly categories = categories;
  protected readonly value = signal<string | string[] | null>([categories[0]]);

  protected readonly selectedValues = computed(() => {
    const value = this.value();
    return (Array.isArray(value) ? value : value ? [value] : []) as (typeof categories)[number][];
  });
}

API Reference

z-comboboxComponent

Root of the combobox. Owns the value, the query, the open state and the keyboard navigation.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[zValue] Selected value. `string` in single mode, `string[]` when `zMultiple` is set. Two-way bindable model<string | string[] | null> null
[zOpen] Open state of the popup. Two-way bindable model<boolean> false
[zMultiple] Enables multiple selection with chips boolean false
[zFilter] Built-in filter strategy applied to the item labels 'contains' | 'startsWith' | 'none' 'contains'
[zFilterFn] Custom filter predicate. Takes precedence over `zFilter` ((label: string, query: string) => boolean) | null null
[zSide] Preferred side of the popup 'top' | 'bottom' 'bottom'
[zAlign] Alignment of the popup against the anchor 'start' | 'center' | 'end' 'start'
[zSideOffset] Distance in px between anchor and popup number 6
[zAlignOffset] Offset in px along the alignment axis number 0
[zAutoHighlight] Highlights the first selectable item while typing, so `Enter` selects it without navigating first boolean false
[zInvalid] Marks the combobox as invalid. Adds `data-invalid` to the host and `aria-invalid` to the input and the chips input boolean false
[zWidth] Width of the combobox 'default' | 'sm' | 'md' | 'lg' | 'full' 'default'
[zDisabled] Whether the combobox is disabled boolean false
[searchable] Whether the input filters the list while typing. When false the input is read-only boolean true
[placeholder] Placeholder shown when the popup is closed string 'Select...'
[searchPlaceholder] Placeholder shown while the popup is open string 'Search...'
[emptyText] Empty state text rendered by the shorthand mode string 'No results found.'
[options] Shorthand mode only — flat list of options rendered by the root ZardComboboxOption[] []
[groups] Shorthand mode only — grouped options rendered by the root ZardComboboxGroup[] []
[ariaLabel] ARIA label forwarded to the input string ''
[ariaDescribedBy] ARIA described-by forwarded to the input string ''
[value] @deprecated Legacy value input, synchronised into `zValue`. Use `[(zValue)]` string | null null
[buttonVariant] @deprecated The trigger is no longer a button, this input has no visual effect 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' 'outline'
(zValueChange) Emitted whenever the selection changes output<string | string[] | null> -
(zOpenChange) Emitted when the popup opens or closes output<boolean> -
(zQueryChange) Emitted when the search query changes output<string> -
(zComboSelected) Emitted with the option that has just been selected output<ZardComboboxOption> -

z-combobox-inputComponent

Input group that hosts the editable combobox input, the trigger and the clear button.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[placeholder] Overrides the placeholder inherited from the root string ''
[zShowTrigger] Renders the chevron trigger button boolean true
[zShowClear] Renders the clear button whenever there is a value boolean false
[zDisabled] Forces the input to be disabled. Inherits from the root when false boolean false

button[z-combobox-trigger]Component

Toggles the popup. Inside a `z-input-group` it stays out of the tab order (`tabindex="-1"`) and hides itself when a clear button is visible. Applied to a standalone `button[z-button]` (popup mode, with the `z-combobox-input` moved inside the `z-combobox-content`) it becomes the popup anchor and receives `tabindex="0"`, and the focus returns to it when the popup closes.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

button[z-combobox-clear]Component

Clears the current selection and the query.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-contentComponent

Popup rendered through the CDK overlay and positioned against the anchor.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[zAnchor] Element the popup is anchored to. Defaults to the input group (or the chips container) ElementRef<HTMLElement> | HTMLElement | null null
[zSide] Overrides the root `zSide` 'top' | 'bottom' | null null
[zAlign] Overrides the root `zAlign` 'start' | 'center' | 'end' | null null
[zSideOffset] Overrides the root `zSideOffset` number | null null
[zAlignOffset] Overrides the root `zAlignOffset` number | null null

z-combobox-listComponent

Scrollable listbox holding the items.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-itemComponent

Selectable option. Hidden automatically when it does not match the query.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[zValue] Value of the option (required) string -
[zLabel] Label used for filtering. Falls back to the projected text content string ''
[zDisabled] Whether the option can be selected boolean false
[zVariant] Visual variant of the option 'default' | 'destructive' 'default'

z-combobox-groupComponent

Groups related items. Hides itself when every child item is filtered out.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-labelComponent

Heading of a group.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-emptyComponent

Empty state, visible only when no item matches the query.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-separatorComponent

Horizontal rule between groups.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-chipsComponent

Container used in multiple mode. Becomes the popup anchor and focuses the chips input on click.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-chipComponent

Single selected value rendered as a removable chip.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[zValue] Value represented by the chip (required) string -
[zShowRemove] Renders the remove button boolean true

button[z-combobox-chip-remove]Component

Removes a value from the selection.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[zValue] Value to remove string ''

input[z-combobox-chips-input]Component

Editable input rendered inside the chips container. Backspace on an empty field removes the last chip.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-combobox-valueComponent

Renders the label of the current selection, typically inside a standalone trigger. Exposes `data-placeholder` while there is no selection, so the placeholder text can be styled.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[placeholder] Text rendered when there is no selection. Falls back to the root `placeholder` string ''
github iconwhatsapp icondiscord iconX icon

Made with ❤ in Brazil. Open source and available on GitHub .