UWC Components
  • Default
  • Material
  • Fluent

On this page

Listbox

A scrollable listbox driven by a SelectOption[] property. Supports single and multi-select, client-side filter, option groups, and full keyboard navigation.

uwc-listbox is a scrollable selection list driven by a SelectOption[] property. It supports single and multi-select with checkboxes, search filtering, option groups, and full keyboard navigation.

Import

All components

import '@uwc/components';

Selected component (Lit / Angular / Vue)

import { UwcListbox } from '@uwc/components/listbox';
customElements.define('uwc-listbox', UwcListbox);

React

import { UwcListbox } from '@uwc/components/react';

Usage

Lit

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('app-demo')
export class AppDemo extends LitElement {
  options = [
    { label: 'New York', value: 'NY' },
    { label: 'London',   value: 'LN' },
  ];
  render() {
    return html`<uwc-listbox .options=${this.options}></uwc-listbox>`;
  }
}

React

import React from 'react';
import { UwcListbox } from '@uwc/components/react';

const options = [
  { label: 'New York', value: 'NY' },
  { label: 'London',   value: 'LN' },
];

export default function App() {
  return <UwcListbox options={options} />;
}

Angular

import { Component } from '@angular/core';
import '@uwc/listbox';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `<uwc-listbox [options]="options"></uwc-listbox>`,
})
export class AppComponent {
  options = [
    { label: 'New York', value: 'NY' },
    { label: 'London',   value: 'LN' },
  ];
}

Vue

import '@uwc/listbox';

export default {
  data() {
    return {
      options: [
        { label: 'New York', value: 'NY' },
        { label: 'London',   value: 'LN' },
      ],
    };
  },
  template: `<uwc-listbox :options="options"></uwc-listbox>`,
};

Basic Usage

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('app-demo')
export class AppDemo extends LitElement {
  options = [
    { label: 'New York',  value: 'NY' },
    { label: 'Rome',      value: 'RM' },
    { label: 'London',    value: 'LN' },
    { label: 'Istanbul',  value: 'IS' },
    { label: 'Paris',     value: 'PA' },
  ];
  render() {
    return html`<uwc-listbox .options=${this.options} style="width:16rem"></uwc-listbox>`;
  }
}
import React from 'react';
import { UwcListbox } from '@uwc/components/react';

export default function App() {
  const options = [
    { label: 'New York',  value: 'NY' },
    { label: 'Rome',      value: 'RM' },
    { label: 'London',    value: 'LN' },
    { label: 'Istanbul',  value: 'IS' },
    { label: 'Paris',     value: 'PA' },
  ];
  return <UwcListbox options={options} style={{ width: '16rem' }} />;
}
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `<uwc-listbox [options]="options" style="width:16rem"></uwc-listbox>`
})
export class AppComponent {
  options = [
    { label: 'New York',  value: 'NY' },
    { label: 'Rome',      value: 'RM' },
    { label: 'London',    value: 'LN' },
    { label: 'Istanbul',  value: 'IS' },
    { label: 'Paris',     value: 'PA' },
  ];
}
export default {
  data() {
    return {
      options: [
        { label: 'New York',  value: 'NY' },
        { label: 'Rome',      value: 'RM' },
        { label: 'London',    value: 'LN' },
        { label: 'Istanbul',  value: 'IS' },
        { label: 'Paris',     value: 'PA' },
      ],
    };
  },
  template: `<uwc-listbox :options="options" style="width:16rem"></uwc-listbox>`
};

Basic

Pass a SelectOption[] array to the options property. Listen to uwc-change to receive the selected value.

import { LitElement, html, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';

@customElement('listbox-basic-demo')
export class AppDemo extends LitElement {
  static styles = css`
    :host { display: block; }
    p { margin: .75rem 0 0; font-size: .875rem; color: #374151; }
    strong { color: #6366f1; }
  `;

  @state() value = null;

  options = [
    { label: 'New York',  value: 'NY' },
    { label: 'Rome',      value: 'RM' },
    { label: 'London',    value: 'LN' },
    { label: 'Istanbul',  value: 'IS' },
    { label: 'Paris',     value: 'PA' },
  ];

  render() {
    return html`
      <uwc-listbox
        .options=${this.options}
        .value=${this.value}
        style="width:16rem"
        @uwc-change=${(e) => { this.value = e.detail.value; }}>
      </uwc-listbox>
      <p>Selected: <strong>${this.value ?? 'none'}</strong></p>
    `;
  }
}
import React, { useState } from 'react';
import { UwcListbox } from '@uwc/components/react';

export default function App() {
  const [value, setValue] = useState(null);
  const options = [
    { label: 'New York',  value: 'NY' },
    { label: 'Rome',      value: 'RM' },
    { label: 'London',    value: 'LN' },
    { label: 'Istanbul',  value: 'IS' },
    { label: 'Paris',     value: 'PA' },
  ];
  return (
    <>
      <UwcListbox
        options={options}
        value={value}
        style={{ width: '16rem' }}
        onUwcChange={(e) => setValue(e.detail.value)}
      />
      <p style={{ marginTop: '.75rem', fontSize: '.875rem', color: '#374151' }}>
        Selected: <strong style={{ color: '#6366f1' }}>{value ?? 'none'}</strong>
      </p>
    </>
  );
}
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <uwc-listbox
      [options]="options"
      [value]="value()"
      style="width:16rem"
      (uwc-change)="value.set($event.detail.value)">
    </uwc-listbox>
    <p style="margin:.75rem 0 0;font-size:.875rem;color:#374151">
      Selected: <strong style="color:#6366f1">{{ value() ?? 'none' }}</strong>
    </p>
  `
})
export class AppComponent {
  readonly value = signal<string | null>(null);
  options = [
    { label: 'New York',  value: 'NY' },
    { label: 'Rome',      value: 'RM' },
    { label: 'London',    value: 'LN' },
    { label: 'Istanbul',  value: 'IS' },
    { label: 'Paris',     value: 'PA' },
  ];
}
export default {
  data() {
    return {
      value: null,
      options: [
        { label: 'New York',  value: 'NY' },
        { label: 'Rome',      value: 'RM' },
        { label: 'London',    value: 'LN' },
        { label: 'Istanbul',  value: 'IS' },
        { label: 'Paris',     value: 'PA' },
      ],
    };
  },
  template: `
    <uwc-listbox
      :options="options"
      :value="value"
      style="width:16rem"
      @uwc-change="value = $event.detail.value">
    </uwc-listbox>
    <p style="margin:.75rem 0 0;font-size:.875rem;color:#374151">
      Selected: <strong style="color:#6366f1">{{ value ?? 'none' }}</strong>
    </p>
  `
};

Multiple selection

Add multiple to enable checkbox-based multi-selection.

import { LitElement, html, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';

@customElement('listbox-multi-demo')
export class AppDemo extends LitElement {
  static styles = css`
    :host { display: block; }
    p { margin: .75rem 0 0; font-size: .875rem; color: #374151; }
  `;

  @state() value = [];

  options = [
    { label: 'HTML',       value: 'html' },
    { label: 'CSS',        value: 'css'  },
    { label: 'JavaScript', value: 'js'   },
    { label: 'TypeScript', value: 'ts'   },
    { label: 'React',      value: 'react'},
    { label: 'Vue',        value: 'vue'  },
  ];

  render() {
    return html`
      <uwc-listbox
        .options=${this.options}
        .value=${this.value}
        multiple
        style="width:16rem"
        @uwc-change=${(e) => { this.value = e.detail.value; }}>
      </uwc-listbox>
      <p>Selected: <strong>${this.value.length ? this.value.join(', ') : 'none'}</strong></p>
    `;
  }
}
import React, { useState } from 'react';
import { UwcListbox } from '@uwc/components/react';

export default function App() {
  const [value, setValue] = useState([]);
  const options = [
    { label: 'HTML',       value: 'html' },
    { label: 'CSS',        value: 'css'  },
    { label: 'JavaScript', value: 'js'   },
    { label: 'TypeScript', value: 'ts'   },
    { label: 'React',      value: 'react'},
    { label: 'Vue',        value: 'vue'  },
  ];
  return (
    <>
      <UwcListbox
        options={options}
        value={value}
        multiple
        style={{ width: '16rem' }}
        onUwcChange={(e) => setValue(e.detail.value)}
      />
      <p style={{ marginTop: '.75rem', fontSize: '.875rem', color: '#374151' }}>
        Selected: <strong>{value.length ? value.join(', ') : 'none'}</strong>
      </p>
    </>
  );
}
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <uwc-listbox
      [options]="options"
      [value]="value()"
      multiple
      style="width:16rem"
      (uwc-change)="value.set($event.detail.value)">
    </uwc-listbox>
    <p style="margin:.75rem 0 0;font-size:.875rem;color:#374151">
      Selected: <strong>{{ value().length ? value().join(', ') : 'none' }}</strong>
    </p>
  `
})
export class AppComponent {
  readonly value = signal<string[]>([]);
  options = [
    { label: 'HTML',       value: 'html' },
    { label: 'CSS',        value: 'css'  },
    { label: 'JavaScript', value: 'js'   },
    { label: 'TypeScript', value: 'ts'   },
    { label: 'React',      value: 'react'},
    { label: 'Vue',        value: 'vue'  },
  ];
}
export default {
  data() {
    return {
      value: [],
      options: [
        { label: 'HTML',       value: 'html' },
        { label: 'CSS',        value: 'css'  },
        { label: 'JavaScript', value: 'js'   },
        { label: 'TypeScript', value: 'ts'   },
        { label: 'React',      value: 'react'},
        { label: 'Vue',        value: 'vue'  },
      ],
    };
  },
  template: `
    <uwc-listbox
      :options="options"
      :value="value"
      multiple
      style="width:16rem"
      @uwc-change="value = $event.detail.value">
    </uwc-listbox>
    <p style="margin:.75rem 0 0;font-size:.875rem;color:#374151">
      Selected: <strong>{{ value.length ? value.join(', ') : 'none' }}</strong>
    </p>
  `
};

With filter

Add filter to show a search input at the top of the list.

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('listbox-filter-demo')
export class AppDemo extends LitElement {
  options = [
    { label: 'United States', value: 'us' },
    { label: 'United Kingdom', value: 'uk' },
    { label: 'Canada',         value: 'ca' },
    { label: 'Germany',        value: 'de' },
    { label: 'France',         value: 'fr' },
    { label: 'Japan',          value: 'jp' },
    { label: 'Australia',      value: 'au' },
  ];
  render() {
    return html`
      <uwc-listbox
        .options=${this.options}
        filter
        filter-placeholder="Search countries..."
        style="width:16rem">
      </uwc-listbox>
    `;
  }
}
import React from 'react';
import { UwcListbox } from '@uwc/components/react';

export default function App() {
  const options = [
    { label: 'United States', value: 'us' },
    { label: 'United Kingdom', value: 'uk' },
    { label: 'Canada',         value: 'ca' },
    { label: 'Germany',        value: 'de' },
    { label: 'France',         value: 'fr' },
    { label: 'Japan',          value: 'jp' },
    { label: 'Australia',      value: 'au' },
  ];
  return (
    <UwcListbox
      options={options}
      filter
      filterPlaceholder="Search countries..."
      style={{ width: '16rem' }}
    />
  );
}
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <uwc-listbox
      [options]="options"
      filter
      filter-placeholder="Search countries..."
      style="width:16rem">
    </uwc-listbox>
  `
})
export class AppComponent {
  options = [
    { label: 'United States', value: 'us' },
    { label: 'United Kingdom', value: 'uk' },
    { label: 'Canada',         value: 'ca' },
    { label: 'Germany',        value: 'de' },
    { label: 'France',         value: 'fr' },
    { label: 'Japan',          value: 'jp' },
    { label: 'Australia',      value: 'au' },
  ];
}
export default {
  data() {
    return {
      options: [
        { label: 'United States', value: 'us' },
        { label: 'United Kingdom', value: 'uk' },
        { label: 'Canada',         value: 'ca' },
        { label: 'Germany',        value: 'de' },
        { label: 'France',         value: 'fr' },
        { label: 'Japan',          value: 'jp' },
        { label: 'Australia',      value: 'au' },
      ],
    };
  },
  template: `
    <uwc-listbox
      :options="options"
      filter
      filter-placeholder="Search countries..."
      style="width:16rem">
    </uwc-listbox>
  `
};

Option groups

Set the group field to render non-selectable section headers.

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('listbox-groups-demo')
export class AppDemo extends LitElement {
  options = [
    { group: 'Fruits',     label: 'Fruits',     value: null },
    { label: 'Apple',      value: 'apple'   },
    { label: 'Banana',     value: 'banana'  },
    { label: 'Cherry',     value: 'cherry'  },
    { group: 'Vegetables', label: 'Vegetables', value: null },
    { label: 'Carrot',     value: 'carrot'  },
    { label: 'Broccoli',   value: 'broccoli'},
  ];
  render() {
    return html`
      <uwc-listbox .options=${this.options} style="width:16rem"></uwc-listbox>
    `;
  }
}
import React from 'react';
import { UwcListbox } from '@uwc/components/react';

export default function App() {
  const options = [
    { group: 'Fruits',     label: 'Fruits',     value: null },
    { label: 'Apple',      value: 'apple'   },
    { label: 'Banana',     value: 'banana'  },
    { label: 'Cherry',     value: 'cherry'  },
    { group: 'Vegetables', label: 'Vegetables', value: null },
    { label: 'Carrot',     value: 'carrot'  },
    { label: 'Broccoli',   value: 'broccoli'},
  ];
  return <UwcListbox options={options} style={{ width: '16rem' }} />;
}
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <uwc-listbox [options]="options" style="width:16rem"></uwc-listbox>
  `
})
export class AppComponent {
  options = [
    { group: 'Fruits',     label: 'Fruits',     value: null },
    { label: 'Apple',      value: 'apple'   },
    { label: 'Banana',     value: 'banana'  },
    { label: 'Cherry',     value: 'cherry'  },
    { group: 'Vegetables', label: 'Vegetables', value: null },
    { label: 'Carrot',     value: 'carrot'  },
    { label: 'Broccoli',   value: 'broccoli'},
  ];
}
export default {
  data() {
    return {
      options: [
        { group: 'Fruits',     label: 'Fruits',     value: null },
        { label: 'Apple',      value: 'apple'   },
        { label: 'Banana',     value: 'banana'  },
        { label: 'Cherry',     value: 'cherry'  },
        { group: 'Vegetables', label: 'Vegetables', value: null },
        { label: 'Carrot',     value: 'carrot'  },
        { label: 'Broccoli',   value: 'broccoli'},
      ],
    };
  },
  template: `
    <uwc-listbox :options="options" style="width:16rem"></uwc-listbox>
  `
};

Disabled items

Set disabled: true on individual options or set disabled on the component to block all interaction.

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('listbox-disabled-demo')
export class AppDemo extends LitElement {
  options = [
    { label: 'Available',   value: 'a' },
    { label: 'Unavailable', value: 'b', disabled: true },
    { label: 'Available',   value: 'c' },
    { label: 'Unavailable', value: 'd', disabled: true },
    { label: 'Available',   value: 'e' },
  ];
  render() {
    return html`
      <uwc-listbox .options=${this.options} style="width:16rem"></uwc-listbox>
    `;
  }
}
import React from 'react';
import { UwcListbox } from '@uwc/components/react';

export default function App() {
  const options = [
    { label: 'Available',   value: 'a' },
    { label: 'Unavailable', value: 'b', disabled: true },
    { label: 'Available',   value: 'c' },
    { label: 'Unavailable', value: 'd', disabled: true },
    { label: 'Available',   value: 'e' },
  ];
  return <UwcListbox options={options} style={{ width: '16rem' }} />;
}
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <uwc-listbox [options]="options" style="width:16rem"></uwc-listbox>
  `
})
export class AppComponent {
  options = [
    { label: 'Available',   value: 'a' },
    { label: 'Unavailable', value: 'b', disabled: true },
    { label: 'Available',   value: 'c' },
    { label: 'Unavailable', value: 'd', disabled: true },
    { label: 'Available',   value: 'e' },
  ];
}
export default {
  data() {
    return {
      options: [
        { label: 'Available',   value: 'a' },
        { label: 'Unavailable', value: 'b', disabled: true },
        { label: 'Available',   value: 'c' },
        { label: 'Unavailable', value: 'd', disabled: true },
        { label: 'Available',   value: 'e' },
      ],
    };
  },
  template: `
    <uwc-listbox :options="options" style="width:16rem"></uwc-listbox>
  `
};

Attributes

Name Type Default Description
options JSON array of SelectOption objects.
value Currently selected value (single) or JSON array (multiple).
multiple Allow multiple selection (shows checkboxes).
filter Show a search filter input.
filter-placeholder Placeholder for filter input.
filter-by Field to filter on. Default: label.
list-style-height Max height of list. Default: 14rem.
disabled Disable the listbox.
invalid Mark as invalid.
fluid Stretch to fill container.
empty-message Text shown when no options match filter. Default: No results found.

Properties

Name Type Default Description
styles CSSResultGroup [styles]
options SelectOption[] [] Accepts a JSON string or will be set programmatically.
value unknown null Single value or array of values (multiple).
multiple boolean false
filter boolean false
filterPlaceholder string 'Search...'
filterBy string 'label'
listStyleHeight string ''
emptyMessage string 'No results found'
disabled boolean false
invalid boolean false
fluid boolean false

Events

Name Type Description
uwc-change CustomEvent Fired on selection change. Detail: { value }.
uwc-filter CustomEvent Fired on filter change. Detail: { query }.

CSS Custom Properties

Name Default Description
--uwc-listbox-radius Border radius.
--uwc-listbox-border Border shorthand.
--uwc-listbox-bg Background color.
--uwc-listbox-item-height Min item height.
--uwc-listbox-font-size Font size.
--uwc-listbox-max-height List scroll max height. Default: 14rem.

CSS Parts

Name Description
container The outer wrapper.
list The <ul> list element.
item Each option <li>.