Listbox

ListBox is used to select one or more values from a list of items.

Usage#

import { Listbox } from 'primereact/listbox';
<Listbox>
    <Listbox.Options />
</Listbox>

Examples#

Basic#

Listbox is used as a controlled component with value and onValueChange properties along with an options collection. Label and value of an option are defined with the optionLabel and optionValue properties respectively. Note that, when options are simple primitive values such as a string array, no optionLabel and optionValue would be necessary.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
basic-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function BasicDemo() {
    const [selectedCity, setSelectedCity] = useState<string | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string | null)}
                options={cities}
                optionLabel="name"
                optionValue="code"
                className="w-full md:w-56"
            >
                <Listbox.Options />
            </Listbox>
        </div>
    );
}

Option#

Options can be defined manually using Listbox.Option component for custom rendering. Each option requires a uKey or index prop for identification. The optionKey property on the Listbox specifies which field from the data corresponds to the option keys.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
option-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function OptionDemo() {
    const [selectedCity, setSelectedCity] = useState<string | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string | null)}
                options={cities}
                optionKey="code"
                className="w-full md:w-56"
            >
                <Listbox.Options>
                    <Listbox.Option uKey="NY">New York</Listbox.Option>
                    <Listbox.Option uKey="RM">Rome</Listbox.Option>
                    <Listbox.Option uKey="LDN">London</Listbox.Option>
                    <Listbox.Option uKey="IST">Istanbul</Listbox.Option>
                    <Listbox.Option uKey="PRS">Paris</Listbox.Option>
                </Listbox.Options>
            </Listbox>
        </div>
    );
}

Selection#

Listbox provides various selection modes. By default, only single item can be selected.

Checkmark#

A checkmark icon is displayed next to the selected option when checkmark property is enabled.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
checkmark-selection-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function CheckmarkSelectionDemo() {
    const [selectedCity, setSelectedCity] = useState<string | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string | null)}
                options={cities}
                optionLabel="name"
                optionValue="code"
                checkmark
                className="w-full md:w-56"
            >
                <Listbox.Options />
            </Listbox>
        </div>
    );
}

Multiple#

Multiple items can be selected by setting multiple property. In this mode, the value binding should be an array.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
multiple-selection-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function MultipleSelectionDemo() {
    const [selectedCity, setSelectedCity] = useState<string[] | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string[] | null)}
                options={cities}
                optionLabel="name"
                optionValue="code"
                multiple
                className="w-full md:w-56"
            >
                <Listbox.Options />
            </Listbox>
        </div>
    );
}

Checkbox#

Checkboxes can be displayed alongside each option by enabling the checkbox property. This works with multiple selection mode to provide a familiar multi-select UI. You can also add a Listbox.Header to display a title or additional controls.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
checkbox-selection-demo.tsx
'use client';

import type { CheckboxChangeEvent } from '@primereact/types/shared/checkbox';
import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Checkbox } from 'primereact/checkbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function CheckboxDemo() {
    const [selectedCity, setSelectedCity] = useState<string[] | null>(null);

    const isAllSelected = cities.every((city) => selectedCity?.includes(city.code));
    const indeterminate = cities.some((city) => selectedCity?.includes(city.code)) && !isAllSelected;

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string[])}
                options={cities}
                optionLabel="name"
                optionValue="code"
                multiple
                checkbox
                className="w-full md:w-56"
            >
                <Listbox.Header>
                    <Checkbox
                        indeterminate={indeterminate}
                        checked={isAllSelected}
                        onCheckedChange={(e: CheckboxChangeEvent) => setSelectedCity(e.checked ? cities.map((city) => city.code) : [])}
                    />
                </Listbox.Header>
                <Listbox.Options />
            </Listbox>
        </div>
    );
}

Custom#

For full control over the option rendering and selection display, a custom render function can be used inside Listbox.Options. The function receives the listbox instance and options data, allowing completely custom option layouts with dynamic selection indicators.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
custom-selection-demo.tsx
'use client';

import type { ListboxOptionsInstance, ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { cn } from '@primeuix/utils';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function CustomSelectionDemo() {
    const [selectedCities, setSelectedCities] = useState<string[] | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCities}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCities(e.value as string[] | null)}
                options={cities}
                multiple
                className="w-full md:w-56"
            >
                <Listbox.Options>
                    {(instance: ListboxOptionsInstance) => {
                        const { listbox, options } = instance;

                        return (options as typeof cities).map((option, index) => {
                            const isSelected = listbox?.isSelected(option);

                            return (
                                <Listbox.Option key={option.code} index={index} className="group">
                                    <div className="flex items-center justify-between w-full">
                                        <span>{option.name}</span>
                                        <i
                                            className={cn('opacity-5 group-hover:opacity-100 transition-opacity duration-500', {
                                                'pi pi-star-fill opacity-80': isSelected,
                                                'pi pi-star': !isSelected
                                            })}
                                        ></i>
                                    </div>
                                </Listbox.Option>
                            );
                        });
                    }}
                </Listbox.Options>
            </Listbox>
        </div>
    );
}

Group#

Options can be organized into groups with headers. Use optionGroupLabel to specify the label field for groups and optionGroupChildren to define the field that contains the items in each group.

  • Germany
  • Berlin
  • Frankfurt
  • Hamburg
  • Munich
  • USA
  • Chicago
  • Los Angeles
  • New York
  • San Francisco
  • Japan
  • Kyoto
  • Osaka
  • Tokyo
  • Yokohama
group-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const groupedCities = [
    {
        label: 'Germany',
        code: 'DE',
        items: [
            { label: 'Berlin', value: 'Berlin' },
            { label: 'Frankfurt', value: 'Frankfurt' },
            { label: 'Hamburg', value: 'Hamburg' },
            { label: 'Munich', value: 'Munich' }
        ]
    },
    {
        label: 'USA',
        code: 'US',
        items: [
            { label: 'Chicago', value: 'Chicago' },
            { label: 'Los Angeles', value: 'Los Angeles' },
            { label: 'New York', value: 'New York' },
            { label: 'San Francisco', value: 'San Francisco' }
        ]
    },
    {
        label: 'Japan',
        code: 'JP',
        items: [
            { label: 'Kyoto', value: 'Kyoto' },
            { label: 'Osaka', value: 'Osaka' },
            { label: 'Tokyo', value: 'Tokyo' },
            { label: 'Yokohama', value: 'Yokohama' }
        ]
    }
];

export default function GroupDemo() {
    const [selectedCity, setSelectedCity] = useState<string | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string | null)}
                options={groupedCities}
                optionLabel="label"
                optionGroupLabel="label"
                optionGroupChildren="items"
                className="w-full md:w-56"
            >
                <Listbox.Options style={{ maxHeight: '250px' }} />
            </Listbox>
        </div>
    );
}

Filter#

Filtering enables searching through the options. Place a Listbox.Filter component inside Listbox.Header to add a search input. Any input component can be used with the as prop and the filtering logic can be controlled with the onChange event.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
filter-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { IconField } from 'primereact/iconfield';
import { InputText } from 'primereact/inputtext';
import { Listbox } from 'primereact/listbox';
import { useMemo, useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function FilterDemo() {
    const [selectedCity, setSelectedCity] = useState<string | null>(null);
    const [filterValue, setFilterValue] = useState<string>('');
    const filteredCities = useMemo(() => cities.filter((city) => city.name.toLowerCase().startsWith(filterValue.toLowerCase())), [filterValue]);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string | null)}
                options={filteredCities}
                optionLabel="name"
                optionValue="code"
                className="w-full md:w-56"
            >
                <Listbox.Header>
                    <IconField>
                        <Listbox.Filter
                            as={InputText}
                            placeholder="Search city"
                            value={filterValue}
                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFilterValue(e.target.value)}
                        />
                        <IconField.Icon>
                            <i className="pi pi-search" />
                        </IconField.Icon>
                    </IconField>
                </Listbox.Header>
                <Listbox.Options />
                <Listbox.Empty>No options found</Listbox.Empty>
            </Listbox>
        </div>
    );
}

Invalid#

When the invalid property is set to true, a visual hint is applied to indicate that the Listbox is in an invalid state. This is commonly used for form validation feedback.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
invalid-demo.tsx
'use client';

import type { ListboxValueChangeEvent } from '@primereact/types/shared/listbox';
import { Listbox } from 'primereact/listbox';
import { useState } from 'react';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function InvalidDemo() {
    const [selectedCity, setSelectedCity] = useState<string | null>(null);

    return (
        <div className="flex justify-center">
            <Listbox
                value={selectedCity}
                onValueChange={(e: ListboxValueChangeEvent) => setSelectedCity(e.value as string | null)}
                options={cities}
                optionLabel="name"
                optionValue="code"
                invalid={selectedCity === null}
                className="w-full md:w-56"
            >
                <Listbox.Options />
            </Listbox>
        </div>
    );
}

Disabled#

When the disabled property is set to true, the Listbox becomes non-interactive and a visual hint is applied to indicate that it cannot be used.

  • New York
  • Rome
  • London
  • Istanbul
  • Paris
disabled-demo.tsx
'use client';

import { Listbox } from 'primereact/listbox';

const cities = [
    { name: 'New York', code: 'NY' },
    { name: 'Rome', code: 'RM' },
    { name: 'London', code: 'LDN' },
    { name: 'Istanbul', code: 'IST' },
    { name: 'Paris', code: 'PRS' }
];

export default function DisabledDemo() {
    return (
        <div className="flex justify-center">
            <Listbox options={cities} optionLabel="name" optionValue="code" disabled className="w-full md:w-56">
                <Listbox.Options />
            </Listbox>
        </div>
    );
}

Accessibility#

Screen Reader#

Value to describe the component can be provided aria-labelledby or aria-label props. The list element has a listbox role with the aria-multiselectable attribute that sets to true when multiple selection is enabled. Each list item has an option role with aria-selected and aria-disabled as their attributes.

Keyboard Support#

KeyFunction
tabMoves focus to the first selected option, if there is none then first option receives the focus.
up arrowMoves focus to the previous option.
down arrowMoves focus to the next option.
enterToggles the selected state of the focused option.
spaceToggles the selected state of the focused option.
homeMoves focus to the first option.
endMoves focus to the last option.
shift + down arrowMoves focus to the next option and toggles the selection state.
shift + up arrowMoves focus to the previous option and toggles the selection state.
shift + spaceSelects the items between the most recently selected option and the focused option.
control + shift + homeSelects the focused option and all the options up to the first one.
control + shift + endSelects the focused option and all the options down to the last one.
control + aSelects all options.
page upJumps visual focus to the first option.
page downJumps visual focus to the last option.
any printable characterMoves focus to the option whose label starts with the characters being typed.

Filter Input Keyboard Support#

KeyFunction
down arrowMoves focus to the next option, if there is none then visual focus does not change.
up arrowMoves focus to the previous option, if there is none then visual focus does not change.
left arrowRemoves the visual focus from the current option and moves input cursor to one character left.
right arrowRemoves the visual focus from the current option and moves input cursor to one character right.
homeMoves input cursor at the end, if not then moves focus to the first option.
endMoves input cursor at the beginning, if not then moves focus to the last option.
enterCloses the popup and moves focus to the multiselect element.
escapeCloses the popup and moves focus to the multiselect element.
tabMoves focus to the next focusable element in the component. If there is none, moves focus to next element in page.