Select
Select is used to choose an item from a collection of options.
Usage#
import { Select } from 'primereact/select';<Select.Root>
<Select.Trigger>
<Select.Value />
<Select.ClearIcon />
<Select.Icon />
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.Header />
<Select.Filter />
<Select.List>
<Select.Options />
</Select.List>
<Select.Footer />
<Select.Empty />
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>Examples#
Basic#
Select 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.
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import type { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Select } from '@primereact/ui/select';
import * as React from 'react';
const languages = [
{ label: 'Select your language', value: '' },
{ label: 'English', value: 'en' },
{ label: 'Deutsch', value: 'de' },
{ label: 'Español', value: 'es' },
{ label: 'Français', value: 'fr' },
{ label: 'Italiano', value: 'it' },
{ label: 'Türkçe', value: 'tr' },
{ label: '日本語', value: 'ja' },
{ label: '中文', value: 'zh' }
];
export default function BasicDemo() {
const [language, setLanguage] = React.useState<string>('');
return (
<div className="flex justify-center">
<Select.Root
value={language}
onValueChange={(e: SelectValueChangeEvent) => setLanguage(e.value as string)}
options={languages}
optionLabel="label"
optionValue="value"
className="w-full md:w-56"
>
<Select.Trigger>
<Select.Value placeholder="Select a language" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Option#
Options can be defined manually using Select.Option component for custom rendering. Each option requires a uKey or index prop for identification. The optionKey property on the Select specifies which field from the data corresponds to the option keys.
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import type { SelectOptionInstance, SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Avatar } from '@primereact/ui/avatar';
import { Select } from '@primereact/ui/select';
import * as React from 'react';
const teamMembers = [
{ id: 1, name: 'Sarah Chen', role: 'Engineering Lead', avatar: 'SC', status: 'away', className: 'bg-amber-400' },
{ id: 2, name: 'Alex Rivera', role: 'Senior Developer', avatar: 'AR', status: 'online', className: 'bg-green-400' },
{ id: 3, name: 'Jordan Kim', role: 'UX Designer', avatar: 'JK', status: 'away', className: 'bg-amber-400' },
{ id: 4, name: 'Taylor Morgan', role: 'Product Manager', avatar: 'TM', status: 'offline', className: 'bg-zinc-400' },
{ id: 5, name: 'Morgan Lee', role: 'DevOps Engineer', avatar: 'ML', status: 'online', className: 'bg-green-400' },
{ id: 6, name: 'Casey Jones', role: 'QA Engineer', avatar: 'CJ', status: 'busy', className: 'bg-red-400' }
];
type TeamMember = (typeof teamMembers)[number] | null;
export default function OptionDemo() {
const [assignee, setAssignee] = React.useState<TeamMember>(null);
return (
<div className="flex justify-center">
<Select.Root
value={assignee}
onValueChange={(e: SelectValueChangeEvent) => setAssignee(e.value as TeamMember)}
options={teamMembers}
optionLabel="name"
className="w-full md:w-56"
>
<Select.Trigger>
<Select.Value>
{assignee ? (
<span className="flex items-center gap-2">
<span className={`inline-block w-2 h-2 rounded-full ${assignee.className}`} />
<span>{assignee.name}</span>
</span>
) : (
<span className="text-surface-400">Select team member...</span>
)}
</Select.Value>
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '16rem' }}>
{teamMembers.map((member, index) => (
<Select.Option key={member.id} index={index} uKey={String(member.id)}>
{(instance: SelectOptionInstance) => {
const { selected } = instance;
return (
<div className="flex items-center gap-3 py-1">
<div className="relative">
<Avatar.Root shape="circle" className="w-8 h-8">
<Avatar.Fallback>{member.avatar}</Avatar.Fallback>
</Avatar.Root>
<span
className={`absolute -bottom-0.5 -right-0.5 w-3 h-3 rounded-full border-2 ${selected ? 'border-primary-emphasis' : 'border-surface-0 dark:border-surface-900'} ${member.className}`}
/>
</div>
<div className="flex flex-col">
<span
className={`font-medium ${selected ? 'text-primary-contrast' : 'text-surface-900 dark:text-surface-0'}`}
>
{member.name}
</span>
<span
className={`text-xs ${selected ? 'text-primary-contrast/70' : 'text-surface-500 dark:text-surface-400'}`}
>
{member.role}
</span>
</div>
</div>
);
}}
</Select.Option>
))}
</Select.Options>
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</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.
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import type { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Select } from '@primereact/ui/select';
import * as React from 'react';
const jobCategories = [
{
label: 'Engineering',
code: 'eng',
items: [
{ label: 'Frontend Developer', value: 'frontend' },
{ label: 'Backend Developer', value: 'backend' },
{ label: 'Full Stack Developer', value: 'fullstack' },
{ label: 'DevOps Engineer', value: 'devops' },
{ label: 'QA Engineer', value: 'qa' }
]
},
{
label: 'Design',
code: 'design',
items: [
{ label: 'UI Designer', value: 'ui' },
{ label: 'UX Designer', value: 'ux' },
{ label: 'Product Designer', value: 'product-design' },
{ label: 'Brand Designer', value: 'brand' }
]
},
{
label: 'Product',
code: 'product',
items: [
{ label: 'Product Manager', value: 'pm' },
{ label: 'Product Owner', value: 'po' },
{ label: 'Business Analyst', value: 'ba' }
]
},
{
label: 'Marketing',
code: 'marketing',
items: [
{ label: 'Growth Manager', value: 'growth' },
{ label: 'Content Strategist', value: 'content' },
{ label: 'SEO Specialist', value: 'seo' }
]
}
];
type Option = (typeof jobCategories)[number]['items'][number] | null;
export default function GroupDemo() {
const [position, setPosition] = React.useState<Option | null>(null);
return (
<div className="flex justify-center">
<Select.Root
value={position}
onValueChange={(e: SelectValueChangeEvent) => setPosition(e.value as Option)}
options={jobCategories}
optionLabel="label"
optionValue="value"
optionGroupLabel="label"
optionGroupChildren="items"
className="w-full md:w-56"
>
<Select.Trigger>
<Select.Value placeholder="Select a position..." />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '18rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Filter#
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import { Search } from '@primeicons/react/search';
import { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { IconField } from '@primereact/ui/iconfield';
import { InputText } from '@primereact/ui/inputtext';
import { Select } from '@primereact/ui/select';
import Image from 'next/image';
import * as React from 'react';
type Country = {
name: string;
code: string;
};
const countries = [
{ name: 'Australia', code: 'AU' },
{ name: 'Brazil', code: 'BR' },
{ name: 'China', code: 'CN' },
{ name: 'Egypt', code: 'EG' },
{ name: 'France', code: 'FR' },
{ name: 'Germany', code: 'DE' },
{ name: 'India', code: 'IN' },
{ name: 'Japan', code: 'JP' },
{ name: 'Spain', code: 'ES' },
{ name: 'Turkey', code: 'TR' },
{ name: 'United States', code: 'US' }
];
export default function FilterDemo() {
const [selectedCountry, setSelectedCountry] = React.useState<Country | null>(null);
const [filterValue, setFilterValue] = React.useState<string>('');
const filteredCountries = React.useMemo(
() => countries.filter((country) => country.name.toLowerCase().startsWith(filterValue.toLowerCase())),
[filterValue]
);
return (
<div className="flex justify-center">
<Select.Root
options={filteredCountries}
optionLabel="name"
value={selectedCountry}
onValueChange={(e: SelectValueChangeEvent) => setSelectedCountry(e.value as Country | null)}
className="w-full md:w-56"
>
<Select.Trigger>
<Select.Value placeholder="Select a Country" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Header>
<IconField.Root>
<Select.Filter
as={InputText}
value={filterValue}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFilterValue(e.target.value)}
/>
<IconField.Icon>
<Search />
</IconField.Icon>
</IconField.Root>
</Select.Header>
<Select.Options style={{ maxHeight: '14rem' }}>
{filteredCountries.map((country, index) => (
<Select.Option key={country.code} index={index} uKey={country.code}>
<div className="flex items-center gap-2">
<Image
alt={country.name}
src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png"
className={`flag flag-${country.code.toLowerCase()} mr-2`}
width={18}
height={12}
style={{ width: '18px', height: '12px' }}
/>
<span>{country.name}</span>
</div>
</Select.Option>
))}
</Select.Options>
<Select.Empty className="text-sm">No countries found</Select.Empty>
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Float Label#
FloatLabel visually integrates a label with its form element. Visit FloatLabel documentation for more information.
import { ChevronDown } from '@primeicons/react/chevron-down';
import { FloatLabel } from '@primereact/ui/floatlabel';
import { Label } from '@primereact/ui/label';
import { Select } from '@primereact/ui/select';
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 FloatLabelDemo() {
return (
<div className="flex flex-wrap justify-center items-end gap-4">
<FloatLabel>
<Select.Root options={cities} optionLabel="name" className="w-full md:w-56">
<Select.Trigger id="over_label">
<Select.Value />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Label htmlFor="over_label">Over Label</Label>
</FloatLabel>
<FloatLabel variant="in">
<Select.Root options={cities} optionLabel="name" className="w-full md:w-56">
<Select.Trigger id="in_label">
<Select.Value />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Label htmlFor="in_label">In Label</Label>
</FloatLabel>
<FloatLabel variant="on">
<Select.Root options={cities} optionLabel="name" className="w-full md:w-56">
<Select.Trigger id="on_label">
<Select.Value />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Label htmlFor="on_label">On Label</Label>
</FloatLabel>
</div>
);
}
Ifta Label#
IftaLabel is used to create infield top aligned labels. Visit IftaLabel documentation for more information.
import { ChevronDown } from '@primeicons/react/chevron-down';
import { IftaLabel } from '@primereact/ui/iftalabel';
import { Label } from '@primereact/ui/label';
import { Select } from '@primereact/ui/select';
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 IftaLabelDemo() {
return (
<div className="flex justify-center">
<IftaLabel>
<Select.Root options={cities} optionLabel="name" variant="filled" className="w-full md:w-56">
<Select.Trigger id="select">
<Select.Value />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Label htmlFor="select" className="mb-2">
City
</Label>
</IftaLabel>
</div>
);
}
Clear Icon#
When Select.ClearIcon component is used, a clear icon is added to reset the Select.
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import { Times } from '@primeicons/react/times';
import type { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Select } from '@primereact/ui/select';
import { Tag } from '@primereact/ui/tag';
import * as React from 'react';
const productCategories = [
{ label: 'Electronics', value: 'electronics', count: 1247 },
{ label: 'Clothing', value: 'clothing', count: 856 },
{ label: 'Garden', value: 'home', count: 634 },
{ label: 'Sports', value: 'sports', count: 421 },
{ label: 'Books', value: 'books', count: 2103 },
{ label: 'Toys', value: 'toys', count: 312 }
];
type CategoryOption = (typeof productCategories)[number] | null;
export default function ClearIconDemo() {
const [category, setCategory] = React.useState<CategoryOption>(null);
return (
<div className="flex flex-col items-center gap-4">
<div className="flex gap-3">
<Select.Root
value={category}
onValueChange={(e: SelectValueChangeEvent) => setCategory(e.value as CategoryOption)}
options={productCategories}
optionLabel="label"
className="w-full md:w-56"
>
<Select.Trigger>
<Select.Value placeholder="Category" />
<Select.ClearIcon>
<Times />
</Select.ClearIcon>
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options>
{productCategories.map((cat, index) => (
<Select.Option key={cat.value} index={index} uKey={cat.value}>
<div className="flex items-center justify-between w-full">
<span>{cat.label}</span>
<Tag severity="secondary" rounded>
{cat.count}
</Tag>
</div>
</Select.Option>
))}
</Select.Options>
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
</div>
);
}
Checkmark#
A checkmark icon is displayed next to the selected option when checkmark property is enabled.
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import type { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Select } from '@primereact/ui/select';
import * as React from 'react';
const themes = [
{ label: 'Light', value: 'light', icon: '☀️', description: 'Clean and bright interface' },
{ label: 'Dark', value: 'dark', icon: '🌙', description: 'Easy on the eyes' },
{ label: 'System', value: 'system', icon: '💻', description: 'Match your device settings' },
{ label: 'High Contrast', value: 'high-contrast', icon: '◐', description: 'Maximum readability' }
];
export default function CheckmarkDemo() {
const [theme, setTheme] = React.useState(themes[2]);
return (
<div className="flex justify-center">
<Select.Root
value={theme}
onValueChange={(e: SelectValueChangeEvent) => setTheme(e.value as (typeof themes)[number])}
options={themes}
optionLabel="label"
checkmark
className="w-full md:w-64"
>
<Select.Trigger>
<Select.Value>
<span className="flex items-center gap-2">
<span>{theme?.icon}</span>
<span>{theme?.label}</span>
</span>
</Select.Value>
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options>
{themes.map((t, index) => (
<Select.Option key={t.value} index={index} uKey={t.value} className="justify-between">
<div className="flex items-center gap-3 py-1">
<span className="text-xl">{t.icon}</span>
<div className="flex flex-col">
<span className="font-medium">{t.label}</span>
<span className="text-xs text-surface-500">{t.description}</span>
</div>
</div>
<Select.Selection className="ml-4" />
</Select.Option>
))}
</Select.Options>
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Multiple#
When multiple prop is enabled, Select allows selecting multiple values. The panel stays open after each selection and the selected items are displayed with a summary text. Use checkmark to show selection indicators.
'use client';
import { Times } from '@primeicons/react';
import { ChevronDownIcon } from '@primereact/icons';
import type { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Select } from '@primereact/ui/select';
import * as React from 'react';
const toppings = [
{ label: 'Pepperoni', value: 'pepperoni' },
{ label: 'Mushrooms', value: 'mushrooms' },
{ label: 'Onions', value: 'onions' },
{ label: 'Black Olives', value: 'olives' },
{ label: 'Green Peppers', value: 'peppers' },
{ label: 'Mozzarella', value: 'mozzarella' },
{ label: 'Basil', value: 'basil' },
{ label: 'Tomatoes', value: 'tomatoes' }
];
export default function MultipleDemo() {
const [selected, setSelected] = React.useState<string[]>([]);
const getLabel = () => {
const first = toppings.find((t) => t.value === selected[0])?.label ?? selected[0];
return selected.length > 1 ? `${first} (+${selected.length - 1} more)` : first;
};
return (
<div className="flex justify-center">
<Select.Root
value={selected}
onValueChange={(e: SelectValueChangeEvent) => setSelected(e.value as string[])}
options={toppings}
optionLabel="label"
optionValue="value"
multiple
checkmark
className="w-full md:w-56"
>
<Select.Trigger>
<Select.Value placeholder="Select toppings">{getLabel()}</Select.Value>
{selected.length > 0 && (
<Select.ClearIcon>
<Times />
</Select.ClearIcon>
)}
<Select.Icon>
<ChevronDownIcon />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Sizes#
Select provides small and large sizes as alternatives to the base.
import { ChevronDown } from '@primeicons/react/chevron-down';
import { Select } from '@primereact/ui/select';
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 SizesDemo() {
return (
<div className="flex flex-col items-center gap-4">
<Select.Root options={cities} optionLabel="name" size="small" className="w-full md:w-56">
<Select.Trigger>
<Select.Value placeholder="Small" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Select.Root options={cities} optionLabel="name" className="w-full md:w-56">
<Select.Trigger>
<Select.Value placeholder="Normal" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Select.Root options={cities} optionLabel="name" size="large" className="w-full md:w-56">
<Select.Trigger>
<Select.Value placeholder="Large" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Fluid#
The fluid prop makes the component take up the full width of its container when set to true.
import { ChevronDown } from '@primeicons/react/chevron-down';
import { Select } from '@primereact/ui/select';
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 FluidDemo() {
return (
<div>
<Select.Root options={cities} optionLabel="name" fluid>
<Select.Trigger>
<Select.Value placeholder="Select a City" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Filled#
Specify the filled property to display the component with a higher visual emphasis than the default outlined style.
import { ChevronDown } from '@primeicons/react/chevron-down';
import { Select } from '@primereact/ui/select';
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 FilledDemo() {
return (
<div className="flex justify-center">
<Select.Root options={cities} optionLabel="name" variant="filled" className="w-full md:w-56">
<Select.Trigger>
<Select.Value placeholder="Select a City" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Disabled#
Use the disabled property to disable a select.
import { ChevronDown } from '@primeicons/react/chevron-down';
import { Select } from '@primereact/ui/select';
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">
<Select.Root options={cities} optionLabel="name" disabled className="w-full md:w-56">
<Select.Trigger>
<Select.Value placeholder="Select a City" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Invalid#
Specify the invalid property to display the component with a red border.
'use client';
import { ChevronDown } from '@primeicons/react/chevron-down';
import type { SelectValueChangeEvent } from '@primereact/types/shared/select';
import { Select } from '@primereact/ui/select';
import * as React 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 [value, setValue] = React.useState<string | null>(null);
const [value2, setValue2] = React.useState<string | null>(null);
return (
<div className="flex flex-wrap justify-center gap-4">
<Select.Root
options={cities}
optionLabel="name"
invalid={!value}
className="w-full md:w-56"
value={value}
onValueChange={(event: SelectValueChangeEvent) => setValue(event.value as string)}
>
<Select.Trigger>
<Select.Value placeholder="Select a City" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Select.Root
options={cities}
optionLabel="name"
invalid={!value2}
variant="filled"
className="w-full md:w-56"
value={value2}
onValueChange={(event: SelectValueChangeEvent) => setValue2(event.value as string)}
>
<Select.Trigger>
<Select.Value placeholder="Select a City" />
<Select.Icon>
<ChevronDown />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner>
<Select.Panel>
<Select.List>
<Select.Options style={{ maxHeight: '14rem' }} />
</Select.List>
</Select.Panel>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</div>
);
}
Accessibility#
Screen Reader#
Value to describe the component can either be provided with aria-labelledby or aria-label props. The select element has a combobox role in addition to aria-haspopup and aria-expanded attributes. If the
editable option is enabled aria-autocomplete is also added. The relation between the combobox and the popup is created with aria-controls and aria-activedescendant attribute is used to instruct screen reader which
option to read during keyboard navigation within the popup list.
The popup list has an id that refers to the aria-controls attribute of the combobox element and uses listbox as the role. Each list item has an option role, an id to match the aria-activedescendant of
the input element along with aria-label, aria-selected and aria-disabled attributes.
Closed State Keyboard Support#
| Key | Function |
|---|---|
tab | Moves focus to the select element. |
space | Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus. |
enter | Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus. |
down arrow | Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus. |
up arrow | Opens the popup and moves visual focus to the selected option, if there is none then last option receives the focus. |
any printable character | Opens the popup and moves focus to the option whose label starts with the characters being typed, if there is none and select is not editable then first option receives the focus. |
Popup Keyboard Support#
| Key | Function |
|---|---|
tab | Moves focus to the next focusable element in the popup. If there is none, the focusable option is selected and the overlay is closed then moves focus to next element in page. |
shift + tab | Moves focus to the previous focusable element in the popup. If there is none, the focusable option is selected and the overlay is closed then moves focus to next element in page. |
enter | Selects the focused option and closes the popup, then moves focus to the select element. |
space | Selects the focused option and closes the popup, then moves focus to the select element. |
escape | Closes the popup, then moves focus to the select element. |
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. |
alt + up arrow | Selects the focused option and closes the popup, then moves focus to the select element. |
left arrow | If the select is editable, removes the visual focus from the current option and moves input cursor to one character left. |
right arrow | If the select is editable, removes the visual focus from the current option and moves input cursor to one character right. |
home | If the select is editable, moves input cursor at the end, if not then moves focus to the first option. |
end | If the select is editable, moves input cursor at the beginning, if not then moves focus to the last option. |
pageUp | Jumps visual focus to first option. |
pageDown | Jumps visual focus to last option. |
any printable character | Moves focus to the option whose label starts with the characters being typed if select is not editable. |
Filter Input Keyboard Support#
| 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 select element. |
escape | Closes the popup and moves focus to the select element. |
tab | Moves focus to the next focusable element in the popup. If there is none, the focusable option is selected and the overlay is closed then moves focus to next element in page. |