Skip to main content

Listbox

The Listbox component is a fully headless and accessible UI primitive for selecting from a list of options. It's inspired by HeadlessUI Listbox, but built natively for Angular.

It is useful for building custom select dropdowns, option pickers, and choice selectors — while giving you complete control over markup and styling.

When to use it

Use Listbox when you need a select component that is:

  • Fully customizable in layout and appearance
  • Accessible with screen readers and keyboard navigation
  • Controlled via Angular templateRefs or Dependency Injection (DI)
  • Compatible with reactive or template-driven forms

Common use cases:

  • Custom select dropdowns
  • Option pickers
  • Choice selectors
  • Filter controls

Anatomy

A complete Listbox is composed of four components:

  • Listbox - The provider and wrapper. Manages internal selection state.
  • ListboxButton - The trigger that toggles the options open or closed.
  • ListboxOptions - The container for all selectable options.
  • ListboxOption - Individual selectable option items.

All four components are standalone and composable.

Features

  • ✅ Accessible by default (ARIA attributes)
  • ✅ Tailwind-friendly (no styles imposed)
  • ✅ Multiple selectors supported:
    • <Listbox>
    • <div ngxListbox>
    • <ngx-headlessui-listbox>
  • ✅ Works with both #templateRefs and Angular DI (ListboxContextService)
  • ✅ Supports multiple instances per page

Installation

Listbox ships as part of the @ngx-headless/ui by default. Install if you haven't already.

npm install @ngx-headless/ui

Import the components directly:

import {
ListboxComponent,
ListboxButtonComponent,
ListboxOptionsComponent,
ListboxOptionComponent,
} from "@ngx-headless/ui";

Usage Examples

Template Reference — Single Listbox

<Listbox #l="ngxListbox" [(modelValue)]="selectedValue">
<ListboxButton [class.active]="l.isOpen()">{{ selectedValue?.name || 'Select option' }}</ListboxButton>
<ListboxOptions *ngIf="l.isOpen()">
<ListboxOption *ngFor="let option of options" [value]="option">
{{ option.name }}
</ListboxOption>
</ListboxOptions>
</Listbox>

Template Reference — Multiple Listboxes (ngFor)

<Listbox *ngFor="let filter of filters" #l="ngxListbox" [(modelValue)]="filter.value">
<ListboxButton>{{ filter.value?.name || filter.placeholder }}</ListboxButton>
<ListboxOptions *ngIf="l.isOpen()">
<ListboxOption *ngFor="let option of filter.options" [value]="option">
{{ option.name }}
</ListboxOption>
</ListboxOptions>
</Listbox>

Accessibility

This component handles

  • aria-expanded on the ListboxButton
  • aria-haspopup="listbox" on the ListboxButton
  • role="listbox" on the Listbox and ListboxOptions
  • role="option" on each ListboxOption
  • aria-selected on the selected ListboxOption
  • Keyboard interaction: toggle on Enter / Space, selection with arrow keys
  • Screen reader compatibility for selection state

Animations

ListboxOptions can be animated freely using Angular's built-in animation system.

Example

Add an animation trigger to your component:

import { trigger, transition, style, animate } from "@angular/animations";

@Component({
animations: [
trigger("slideDown", [
transition(":enter", [
style({ opacity: 0, transform: "translateY(-10px)" }),
animate("150ms ease-out", style({ opacity: 1, transform: "translateY(0)" })),
]),
transition(":leave", [
animate("100ms ease-in", style({ opacity: 0, transform: "translateY(-10px)" })),
]),
]),
],
})
export class ExampleComponent {}

Use it in the template with *ngIf:

<ListboxOptions *ngIf="listbox.isOpen()" @slideDown>
Options go here.
</ListboxOptions>

Component API

ListboxComponent

InputTypeDescription
modelValueanyCurrently selected value
classstringClass for styling wrapper
OutputTypeDescription
modelValueChangeEventEmitter<any>Emits when selection changes
MethodDescription
isOpen()Returns true if options open
toggle()Toggles options open/close
open()Opens options
close()Closes options
selectValue()Selects a specific value

ListboxButtonComponent

  • Automatically binds aria-expanded and aria-haspopup
  • Toggles options on click and keyboard interaction

ListboxOptionsComponent

  • Visible only when Listbox is open
  • Can be styled or animated freely
  • hidden attribute used for visibility

ListboxOptionComponent

InputTypeDescription
valueanyValue for this option
disabledbooleanPrevents selection if true
classstringClass applied to the option
OutputTypeDescription
selectedEventEmitter<any>Emits when option is selected

See Also