ListBox is used to select one or more values from a list of items.
import { Listbox } from 'primereact/listbox';<Listbox>
<Listbox.Options />
</Listbox>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.
'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>
);
}
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.
'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>
);
}
Listbox provides various selection modes. By default, only single item can be selected.
A checkmark icon is displayed next to the selected option when checkmark property is enabled.
'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 items can be selected by setting multiple property. In this mode, the value binding should be an array.
'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>
);
}
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.
'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>
);
}
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.
'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>
);
}
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.
'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>
);
}
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.
'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>
);
}
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.
'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>
);
}
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.
'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>
);
}
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.
| Key | Function |
|---|---|
tab | Moves focus to the first selected option, if there is none then first option receives the focus. |
up arrow | Moves focus to the previous option. |
down arrow | Moves focus to the next option. |
enter | Toggles the selected state of the focused option. |
space | Toggles the selected state of the focused option. |
home | Moves focus to the first option. |
end | Moves focus to the last option. |
shift + down arrow | Moves focus to the next option and toggles the selection state. |
shift + up arrow | Moves focus to the previous option and toggles the selection state. |
shift + space | Selects the items between the most recently selected option and the focused option. |
control + shift + home | Selects the focused option and all the options up to the first one. |
control + shift + end | Selects the focused option and all the options down to the last one. |
control + a | Selects all options. |
page up | Jumps visual focus to the first option. |
page down | Jumps visual focus to the last option. |
any printable character | Moves focus to the option whose label starts with the characters being typed. |
| Key | Function |
|---|---|
down arrow | Moves focus to the next option, if there is none then visual focus does not change. |
up arrow | Moves focus to the previous option, if there is none then visual focus does not change. |
left arrow | Removes the visual focus from the current option and moves input cursor to one character left. |
right arrow | Removes the visual focus from the current option and moves input cursor to one character right. |
home | Moves input cursor at the end, if not then moves focus to the first option. |
end | Moves input cursor at the beginning, if not then moves focus to the last option. |
enter | Closes the popup and moves focus to the multiselect element. |
escape | Closes the popup and moves focus to the multiselect element. |
tab | Moves focus to the next focusable element in the component. If there is none, moves focus to next element in page. |