ComboBox
A dropdown list that allows users to type a value to filter the options.
import * as React from 'react';
import { ComboBox } from '@itwin/itwinui-react';
export default () => {
const options = React.useMemo(
() => [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Grapefruit', value: 'grapefruit' },
{ label: 'Lychee', value: 'lychee' },
{ label: 'Kiwi', value: 'kiwi' },
{ label: 'Orange', value: 'orange' },
],
[],
);
return (
<ComboBox
options={options}
inputProps={{ placeholder: 'Pick a fruit, any fruit' }}
/>
);
};
The combobox component is a dropdown menu that allows filtering. Values can be selected either using mouse clicks or using the Enter key.
Variants
Controlled
The value
property allows you to control of the selected value. If multiselect is enabled, value
will be an array of values.
import * as React from 'react';
import { ComboBox } from '@itwin/itwinui-react';
export default () => {
const [value, setValue] = React.useState('green');
const options = React.useMemo(
() => [
{ label: 'Red', value: 'red' },
{ label: 'Orange', value: 'orange' },
{ label: 'Yellow', value: 'yellow' },
{ label: 'Green', value: 'green' },
{ label: 'Blue', value: 'blue' },
{ label: 'Purple', value: 'purple' },
],
[],
);
return (
<ComboBox
options={options}
inputProps={{ placeholder: 'Select a color' }}
value={value}
onChange={setValue}
/>
);
};
Messages
Add a message below the combobox with the message
property.
import * as React from 'react';
import { ComboBox } from '@itwin/itwinui-react';
export default () => {
const [value, setValue] = React.useState('');
const options = React.useMemo(
() => [
{ label: 'Helvetica', value: 'helvetica' },
{ label: 'Futura', value: 'futura' },
{ label: 'Verdana', value: 'verdana' },
{ label: 'Times New Roman', value: 'roman' },
{ label: 'Arial', value: 'arial' },
{ label: 'Rockwell', value: 'rockwell' },
{ label: 'Bodoni', value: 'bodoni' },
{ label: 'Garamond', value: 'garamond' },
],
[],
);
return (
<ComboBox
options={options}
message='This font will be used in your signature.'
inputProps={{ placeholder: 'Choose a font' }}
onChange={setValue}
value={value}
/>
);
};
Use the StatusMessage
component if you want a more complex message. In the example below, StatusMessage
is used to add an icon to the message.
import * as React from 'react';
import { ComboBox, StatusMessage } from '@itwin/itwinui-react';
import { SvgClock } from '@itwin/itwinui-icons-react';
export default () => {
const [value, setValue] = React.useState('');
const options = React.useMemo(
() => [
{ label: '9:30 AM', value: '9:30' },
{ label: '10:00 AM', value: '10:00' },
{ label: '10:30 AM', value: '10:30' },
{ label: '1:00 PM', value: '1:00' },
{ label: '2:00 PM', value: '2:00' },
{ label: '2:30 PM', value: '2:30' },
{ label: '4:30 PM', value: '4:30' },
],
[],
);
return (
<ComboBox
options={options}
message={
<StatusMessage startIcon={<SvgClock />}>
Appointments run for 30 minutes.
</StatusMessage>
}
inputProps={{ placeholder: 'Select appointment time' }}
onChange={setValue}
value={value}
/>
);
};
Status
Comboboxes can have different statuses applied to them. A status will give the combobox a colored border and an associated icon below. The available statuses are:
positive
warning
negative
import * as React from 'react';
import { ComboBox } from '@itwin/itwinui-react';
export default () => {
const [value, setValue] = React.useState('');
const options = React.useMemo(
() => [
{ label: 'Alabama', value: 'AL' },
{ label: 'Alaska', value: 'AK' },
{ label: 'Arizona', value: 'AZ' },
{ label: 'Arkansas', value: 'AR' },
{ label: 'California', value: 'CA' },
{ label: 'Colorado', value: 'CO' },
{ label: 'Connecticut', value: 'CT' },
{ label: 'Delaware', value: 'DE' },
{ label: 'Florida', value: 'FL' },
{ label: 'Georgia', value: 'GA' },
{ label: 'Hawaii', value: 'HI' },
{ label: 'Idaho', value: 'ID' },
{ label: 'Illinois', value: 'IL' },
{ label: 'Indiana', value: 'IN' },
{ label: 'Iowa', value: 'IA' },
{ label: 'Kansas', value: 'KS' },
{ label: 'Kentucky', value: 'KY' },
{ label: 'Louisiana', value: 'LA' },
{ label: 'Maine', value: 'ME' },
{ label: 'Maryland', value: 'MD' },
{ label: 'Massachusetts', value: 'MA' },
{ label: 'Michigan', value: 'MI' },
{ label: 'Minnesota', value: 'MN' },
{ label: 'Mississippi', value: 'MS' },
{ label: 'Missouri', value: 'MO' },
{ label: 'Montana', value: 'MT' },
{ label: 'Nebraska', value: 'NE' },
{ label: 'Nevada', value: 'NV' },
{ label: 'New Hampshire', value: 'NH' },
{ label: 'New Jersey', value: 'NJ' },
{ label: 'New Mexico', value: 'NM' },
{ label: 'New York', value: 'NY' },
{ label: 'North Carolina', value: 'NC' },
{ label: 'North Dakota', value: 'ND' },
{ label: 'Ohio', value: 'OH' },
{ label: 'Oklahoma', value: 'OK' },
{ label: 'Oregon', value: 'OR' },
{ label: 'Pennsylvania', value: 'PA' },
{ label: 'Rhode Island ', value: 'RI' },
{ label: 'South Carolina', value: 'SC' },
{ label: 'South Dakota', value: 'SD' },
{ label: 'Tennessee', value: 'TN' },
{ label: 'Texas', value: 'TX' },
{ label: 'Utah', value: 'UT' },
{ label: 'Vermont', value: 'VT' },
{ label: 'Virginia', value: 'VA' },
{ label: 'Washington', value: 'WA' },
{ label: 'West Virginia', value: 'WV' },
{ label: 'Wisconsin', value: 'WI' },
{ label: 'Wyoming', value: 'WY' },
],
[],
);
return (
<ComboBox
options={options}
inputProps={{ placeholder: 'Select your state' }}
onChange={setValue}
value={value}
status={value === '' ? 'negative' : 'positive'}
message={value === '' ? 'Required' : ''}
/>
);
};
Multiselect
Set the property multiple
to true to allow users to select more than one value.
import * as React from 'react';
import { ComboBox, Label, InputGrid } from '@itwin/itwinui-react';
export default () => {
const options = React.useMemo(
() => [
{ label: 'Apartments', value: 'apartments' },
{ label: 'Houses', value: 'houses' },
{ label: 'Lofts', value: 'lofts' },
{ label: 'Condos', value: 'condos' },
{ label: 'Townhomes', value: 'townhomes' },
],
[],
);
const [selectedOptions, setSelectedOptions] = React.useState([
'townhomes',
'condos',
]);
return (
<InputGrid>
<Label htmlFor='housing-input'> Select housing type </Label>
<ComboBox
options={options}
inputProps={{ id: 'housing-input', placeholder: 'Housing type' }}
multiple
value={selectedOptions}
onChange={(selected) => {
setSelectedOptions(selected);
}}
/>
</InputGrid>
);
};
When multiple
is true
, a clearFilterOnOptionToggle
prop is available. Possible values:
true
(default): Filter is cleared when an option is toggled. Useful when users would likely want to re-filter after toggling an option.false
: Filter is not cleared when an option is toggled. This is useful when users would likely want to toggle multiple options from the same filtered results.
import * as React from 'react';
import {
ComboBox,
Label,
InputGrid,
Flex,
Divider,
Checkbox,
} from '@itwin/itwinui-react';
export default () => {
const options = React.useMemo(
() => [
{ label: 'Apartments', value: 'apartments' },
{ label: 'Houses', value: 'houses' },
{ label: 'Lofts', value: 'lofts' },
{ label: 'Condos', value: 'condos' },
{ label: 'Townhomes', value: 'townhomes' },
],
[],
);
const [selectedOptions, setSelectedOptions] = React.useState([
'townhomes',
'condos',
]);
const [clearFilterOnOptionToggle, setClearFilterOnOptionToggle] =
React.useState(true);
return (
<Flex id='main-story-container' flexDirection='column' alignItems='stretch'>
<InputGrid>
<Label htmlFor='housing-input'> Select housing type </Label>
<ComboBox
options={options}
inputProps={{ id: 'housing-input', placeholder: 'Housing type' }}
multiple
value={selectedOptions}
onChange={(selected) => {
setSelectedOptions(selected);
}}
clearFilterOnOptionToggle={clearFilterOnOptionToggle}
/>
</InputGrid>
<Divider />
<Checkbox
checked={clearFilterOnOptionToggle}
onChange={(e) => setClearFilterOnOptionToggle(e.target.checked)}
label='clearFilterOnOptionToggle'
/>
</Flex>
);
};
Virtualized
If you expect the combobox to have a very long list of items, you can set enableVirtualization
to true. This will use virtualization for the scrollable dropdown list.
import * as React from 'react';
import { ComboBox } from '@itwin/itwinui-react';
export default () => {
const [value, setValue] = React.useState('');
const options = React.useMemo(
() => [
{ label: 'Afghanistan', value: 'AF' },
{ label: 'Ã…land Islands', value: 'AX' },
{ label: 'Albania', value: 'AL' },
{ label: 'Algeria', value: 'DZ' },
{ label: 'American Samoa', value: 'AS' },
{ label: 'Andorra', value: 'AD' },
{ label: 'Angola', value: 'AO' },
{ label: 'Anguilla', value: 'AI' },
{ label: 'Antarctica', value: 'AQ' },
{ label: 'Antigua and Barbuda', value: 'AG' },
{ label: 'Argentina', value: 'AR' },
{ label: 'Armenia', value: 'AM' },
{ label: 'Aruba', value: 'AW' },
{ label: 'Australia', value: 'AU' },
{ label: 'Austria', value: 'AT' },
{ label: 'Azerbaijan', value: 'AZ' },
{ label: 'Bahamas', value: 'BS' },
{ label: 'Bahrain', value: 'BH' },
{ label: 'Bangladesh', value: 'BD' },
{ label: 'Barbados', value: 'BB' },
{ label: 'Belarus', value: 'BY' },
{ label: 'Belgium', value: 'BE' },
{ label: 'Belize', value: 'BZ' },
{ label: 'Benin', value: 'BJ' },
{ label: 'Bermuda', value: 'BM' },
{ label: 'Bhutan', value: 'BT' },
{ label: 'Bolivia', value: 'BO' },
{ label: 'Bosnia and Herzegovina', value: 'BA' },
{ label: 'Botswana', value: 'BW' },
{ label: 'Bouvet Island', value: 'BV' },
{ label: 'Brazil', value: 'BR' },
{ label: 'British Indian Ocean Territory', value: 'IO' },
{ label: 'Brunei Darussalam', value: 'BN' },
{ label: 'Bulgaria', value: 'BG' },
{ label: 'Burkina Faso', value: 'BF' },
{ label: 'Burundi', value: 'BI' },
{ label: 'Cambodia', value: 'KH' },
{ label: 'Cameroon', value: 'CM' },
{ label: 'Canada', value: 'CA' },
{ label: 'Cape Verde', value: 'CV' },
{ label: 'Cayman Islands', value: 'KY' },
{ label: 'Central African Republic', value: 'CF' },
{ label: 'Chad', value: 'TD' },
{ label: 'Chile', value: 'CL' },
{ label: 'China', value: 'CN' },
{ label: 'Christmas Island', value: 'CX' },
{ label: 'Cocos (Keeling) Islands', value: 'CC' },
{ label: 'Colombia', value: 'CO' },
{ label: 'Comoros', value: 'KM' },
{ label: 'Congo', value: 'CG' },
{ label: 'Congo, The Democratic Republic of the', value: 'CD' },
{ label: 'Cook Islands', value: 'CK' },
{ label: 'Costa Rica', value: 'CR' },
{ label: "Cote D'Ivoire", value: 'CI' },
{ label: 'Croatia', value: 'HR' },
{ label: 'Cuba', value: 'CU' },
{ label: 'Cyprus', value: 'CY' },
{ label: 'Czech Republic', value: 'CZ' },
{ label: 'Denmark', value: 'DK' },
{ label: 'Djibouti', value: 'DJ' },
{ label: 'Dominica', value: 'DM' },
{ label: 'Dominican Republic', value: 'DO' },
{ label: 'Ecuador', value: 'EC' },
{ label: 'Egypt', value: 'EG' },
{ label: 'El Salvador', value: 'SV' },
{ label: 'Equatorial Guinea', value: 'GQ' },
{ label: 'Eritrea', value: 'ER' },
{ label: 'Estonia', value: 'EE' },
{ label: 'Ethiopia', value: 'ET' },
{ label: 'Falkland Islands (Malvinas)', value: 'FK' },
{ label: 'Faroe Islands', value: 'FO' },
{ label: 'Fiji', value: 'FJ' },
{ label: 'Finland', value: 'FI' },
{ label: 'France', value: 'FR' },
{ label: 'French Guiana', value: 'GF' },
{ label: 'French Polynesia', value: 'PF' },
{ label: 'French Southern Territories', value: 'TF' },
{ label: 'Gabon', value: 'GA' },
{ label: 'Gambia', value: 'GM' },
{ label: 'Georgia', value: 'GE' },
{ label: 'Germany', value: 'DE' },
{ label: 'Ghana', value: 'GH' },
{ label: 'Gibraltar', value: 'GI' },
{ label: 'Greece', value: 'GR' },
{ label: 'Greenland', value: 'GL' },
{ label: 'Grenada', value: 'GD' },
{ label: 'Guadeloupe', value: 'GP' },
{ label: 'Guam', value: 'GU' },
{ label: 'Guatemala', value: 'GT' },
{ label: 'Guernsey', value: 'GG' },
{ label: 'Guinea', value: 'GN' },
{ label: 'Guinea-Bissau', value: 'GW' },
{ label: 'Guyana', value: 'GY' },
{ label: 'Haiti', value: 'HT' },
{ label: 'Heard Island and Mcdonald Islands', value: 'HM' },
{ label: 'Holy See (Vatican City State)', value: 'VA' },
{ label: 'Honduras', value: 'HN' },
{ label: 'Hong Kong', value: 'HK' },
{ label: 'Hungary', value: 'HU' },
{ label: 'Iceland', value: 'IS' },
{ label: 'India', value: 'IN' },
{ label: 'Indonesia', value: 'ID' },
{ label: 'Iran, Islamic Republic Of', value: 'IR' },
{ label: 'Iraq', value: 'IQ' },
{ label: 'Ireland', value: 'IE' },
{ label: 'Isle of Man', value: 'IM' },
{ label: 'Israel', value: 'IL' },
{ label: 'Italy', value: 'IT' },
{ label: 'Jamaica', value: 'JM' },
{ label: 'Japan', value: 'JP' },
{ label: 'Jersey', value: 'JE' },
{ label: 'Jordan', value: 'JO' },
{ label: 'Kazakhstan', value: 'KZ' },
{ label: 'Kenya', value: 'KE' },
{ label: 'Kiribati', value: 'KI' },
{ label: "Korea, Democratic People'S Republic of", value: 'KP' },
{ label: 'Korea, Republic of', value: 'KR' },
{ label: 'Kuwait', value: 'KW' },
{ label: 'Kyrgyzstan', value: 'KG' },
{ label: "Lao People'S Democratic Republic", value: 'LA' },
{ label: 'Latvia', value: 'LV' },
{ label: 'Lebanon', value: 'LB' },
{ label: 'Lesotho', value: 'LS' },
{ label: 'Liberia', value: 'LR' },
{ label: 'Libyan Arab Jamahiriya', value: 'LY' },
{ label: 'Liechtenstein', value: 'LI' },
{ label: 'Lithuania', value: 'LT' },
{ label: 'Luxembourg', value: 'LU' },
{ label: 'Macao', value: 'MO' },
{ label: 'Macedonia, The Former Yugoslav Republic of', value: 'MK' },
{ label: 'Madagascar', value: 'MG' },
{ label: 'Malawi', value: 'MW' },
{ label: 'Malaysia', value: 'MY' },
{ label: 'Maldives', value: 'MV' },
{ label: 'Mali', value: 'ML' },
{ label: 'Malta', value: 'MT' },
{ label: 'Marshall Islands', value: 'MH' },
{ label: 'Martinique', value: 'MQ' },
{ label: 'Mauritania', value: 'MR' },
{ label: 'Mauritius', value: 'MU' },
{ label: 'Mayotte', value: 'YT' },
{ label: 'Mexico', value: 'MX' },
{ label: 'Micronesia, Federated States of', value: 'FM' },
{ label: 'Moldova, Republic of', value: 'MD' },
{ label: 'Monaco', value: 'MC' },
{ label: 'Mongolia', value: 'MN' },
{ label: 'Montserrat', value: 'MS' },
{ label: 'Morocco', value: 'MA' },
{ label: 'Mozambique', value: 'MZ' },
{ label: 'Myanmar', value: 'MM' },
{ label: 'Namibia', value: 'NA' },
{ label: 'Nauru', value: 'NR' },
{ label: 'Nepal', value: 'NP' },
{ label: 'Netherlands', value: 'NL' },
{ label: 'Netherlands Antilles', value: 'AN' },
{ label: 'New Caledonia', value: 'NC' },
{ label: 'New Zealand', value: 'NZ' },
{ label: 'Nicaragua', value: 'NI' },
{ label: 'Niger', value: 'NE' },
{ label: 'Nigeria', value: 'NG' },
{ label: 'Niue', value: 'NU' },
{ label: 'Norfolk Island', value: 'NF' },
{ label: 'Northern Mariana Islands', value: 'MP' },
{ label: 'Norway', value: 'NO' },
{ label: 'Oman', value: 'OM' },
{ label: 'Pakistan', value: 'PK' },
{ label: 'Palau', value: 'PW' },
{ label: 'Palestinian Territory, Occupied', value: 'PS' },
{ label: 'Panama', value: 'PA' },
{ label: 'Papua New Guinea', value: 'PG' },
{ label: 'Paraguay', value: 'PY' },
{ label: 'Peru', value: 'PE' },
{ label: 'Philippines', value: 'PH' },
{ label: 'Pitcairn', value: 'PN' },
{ label: 'Poland', value: 'PL' },
{ label: 'Portugal', value: 'PT' },
{ label: 'Puerto Rico', value: 'PR' },
{ label: 'Qatar', value: 'QA' },
{ label: 'Reunion', value: 'RE' },
{ label: 'Romania', value: 'RO' },
{ label: 'Russian Federation', value: 'RU' },
{ label: 'RWANDA', value: 'RW' },
{ label: 'Saint Helena', value: 'SH' },
{ label: 'Saint Kitts and Nevis', value: 'KN' },
{ label: 'Saint Lucia', value: 'LC' },
{ label: 'Saint Pierre and Miquelon', value: 'PM' },
{ label: 'Saint Vincent and the Grenadines', value: 'VC' },
{ label: 'Samoa', value: 'WS' },
{ label: 'San Marino', value: 'SM' },
{ label: 'Sao Tome and Principe', value: 'ST' },
{ label: 'Saudi Arabia', value: 'SA' },
{ label: 'Senegal', value: 'SN' },
{ label: 'Serbia and Montenegro', value: 'CS' },
{ label: 'Seychelles', value: 'SC' },
{ label: 'Sierra Leone', value: 'SL' },
{ label: 'Singapore', value: 'SG' },
{ label: 'Slovakia', value: 'SK' },
{ label: 'Slovenia', value: 'SI' },
{ label: 'Solomon Islands', value: 'SB' },
{ label: 'Somalia', value: 'SO' },
{ label: 'South Africa', value: 'ZA' },
{ label: 'South Georgia and the South Sandwich Islands', value: 'GS' },
{ label: 'Spain', value: 'ES' },
{ label: 'Sri Lanka', value: 'LK' },
{ label: 'Sudan', value: 'SD' },
{ label: 'Surilabel', value: 'SR' },
{ label: 'Svalbard and Jan Mayen', value: 'SJ' },
{ label: 'Swaziland', value: 'SZ' },
{ label: 'Sweden', value: 'SE' },
{ label: 'Switzerland', value: 'CH' },
{ label: 'Syrian Arab Republic', value: 'SY' },
{ label: 'Taiwan, Province of China', value: 'TW' },
{ label: 'Tajikistan', value: 'TJ' },
{ label: 'Tanzania, United Republic of', value: 'TZ' },
{ label: 'Thailand', value: 'TH' },
{ label: 'Timor-Leste', value: 'TL' },
{ label: 'Togo', value: 'TG' },
{ label: 'Tokelau', value: 'TK' },
{ label: 'Tonga', value: 'TO' },
{ label: 'Trinidad and Tobago', value: 'TT' },
{ label: 'Tunisia', value: 'TN' },
{ label: 'Turkey', value: 'TR' },
{ label: 'Turkmenistan', value: 'TM' },
{ label: 'Turks and Caicos Islands', value: 'TC' },
{ label: 'Tuvalu', value: 'TV' },
{ label: 'Uganda', value: 'UG' },
{ label: 'Ukraine', value: 'UA' },
{ label: 'United Arab Emirates', value: 'AE' },
{ label: 'United Kingdom', value: 'GB' },
{ label: 'United States', value: 'US' },
{ label: 'United States Minor Outlying Islands', value: 'UM' },
{ label: 'Uruguay', value: 'UY' },
{ label: 'Uzbekistan', value: 'UZ' },
{ label: 'Vanuatu', value: 'VU' },
{ label: 'Venezuela', value: 'VE' },
{ label: 'Viet Nam', value: 'VN' },
{ label: 'Virgin Islands, British', value: 'VG' },
{ label: 'Virgin Islands, U.S.', value: 'VI' },
{ label: 'Wallis and Futuna', value: 'WF' },
{ label: 'Western Sahara', value: 'EH' },
{ label: 'Yemen', value: 'YE' },
{ label: 'Zambia', value: 'ZM' },
{ label: 'Zimbabwe', value: 'ZW' },
],
[],
);
return (
<ComboBox
options={options}
inputProps={{ placeholder: 'Select a country' }}
onChange={setValue}
value={value}
enableVirtualization
/>
);
};
Usage
Labels
You can use a Label component alongside the combobox to add a label. Note that passing the same id to the label as htmlFor
and to the combobox as id
in inputProps
will allow users to open the combobox by clicking on the label.
import * as React from 'react';
import { ComboBox, Label, InputGrid } from '@itwin/itwinui-react';
export default () => {
const [breakfast, setBreakfast] = React.useState('');
const [lunch, setLunch] = React.useState('');
const breakfastOptions = React.useMemo(
() => [
{ label: 'Oatmeal parfait', value: 'parfait' },
{ label: 'Waffle', value: 'waffle' },
{ label: 'Omelette', value: 'omelette' },
{ label: 'Breakfast sandwich', value: 'sandwich' },
],
[],
);
const lunchOptions = React.useMemo(
() => [
{ label: 'BLT', value: 'blt' },
{ label: 'Salad', value: 'salad' },
{ label: 'Chicken sandwich', value: 'chicken' },
{ label: 'Tortilla soup', value: 'soup' },
{ label: 'Fettucini alfredo', value: 'pasta' },
],
[],
);
return (
<>
<InputGrid>
<Label htmlFor='breakfast-input'>Breakfast</Label>
<ComboBox
options={breakfastOptions}
value={breakfast}
onChange={setBreakfast}
inputProps={{
id: 'breakfast-input', // passing id to inputProps so it can be used in Label htmlFor
placeholder: 'Choose your meal',
}}
/>
</InputGrid>
<InputGrid>
<Label htmlFor='lunch-input'>Lunch</Label>
<ComboBox
options={lunchOptions}
value={lunch}
onChange={setLunch}
inputProps={{
id: 'lunch-input', // passing id to inputProps so it can be used in Label htmlFor
placeholder: 'Choose your meal',
}}
/>
</InputGrid>
</>
);
};
Disabled items
To disable specific items in the list, add the disabled
property to the options.
import * as React from 'react';
import { ComboBox } from '@itwin/itwinui-react';
export default () => {
const [value, setValue] = React.useState('');
const courses = React.useMemo(
() => [
{ label: 'User Interface Design', value: '6620', hasPrereq: false },
{ label: 'Machine Learning', value: '6630', hasPrereq: false },
{ label: 'Quality Assurance', value: '5710', hasPrereq: true },
{ label: 'Data mining', value: '5130', hasPrereq: true },
{ label: 'Digital Forensics', value: '5350', hasPrereq: true },
{ label: 'Wireless and Mobile Networks', value: '3370', hasPrereq: true },
{
label: 'Software Reverse Engineering',
value: '7720',
hasPrereq: false,
},
{ label: 'Web Application Development', value: '5000', hasPrereq: true },
{ label: 'Database Systems', value: '5120', hasPrereq: true },
],
[],
);
const options = React.useMemo(
() =>
courses.map((course, index) => ({
...course,
sublabel: `COMP ${course.value}${
course.hasPrereq ? ' - needs pre-requisite' : ''
}`,
disabled: course.hasPrereq,
})),
[],
);
return (
<ComboBox
options={options}
value={value}
onChange={setValue}
inputProps={{ placeholder: 'Select elective' }}
/>
);
};
Loading
If you expect to take a while to retrieve the options, you can show skeletons in the options list while the items are loading. Use MenuItemSkeleton
to achieve this as in the example below.
import * as React from 'react';
import { ComboBox, MenuItemSkeleton } from '@itwin/itwinui-react';
export default () => {
const countriesList = React.useMemo(
() => [
{ label: 'Afghanistan', value: 'AF' },
{ label: 'Ã…land Islands', value: 'AX' },
{ label: 'Albania', value: 'AL' },
{ label: 'Algeria', value: 'DZ' },
{ label: 'American Samoa', value: 'AS' },
{ label: 'Andorra', value: 'AD' },
{ label: 'Angola', value: 'AO' },
{ label: 'Anguilla', value: 'AI' },
{ label: 'Antarctica', value: 'AQ' },
{ label: 'Antigua and Barbuda', value: 'AG' },
{ label: 'Argentina', value: 'AR' },
{ label: 'Armenia', value: 'AM' },
{ label: 'Aruba', value: 'AW' },
{ label: 'Australia', value: 'AU' },
{ label: 'Austria', value: 'AT' },
{ label: 'Azerbaijan', value: 'AZ' },
{ label: 'Bahamas', value: 'BS' },
{ label: 'Bahrain', value: 'BH' },
{ label: 'Bangladesh', value: 'BD' },
{ label: 'Barbados', value: 'BB' },
{ label: 'Belarus', value: 'BY' },
{ label: 'Belgium', value: 'BE' },
{ label: 'Belize', value: 'BZ' },
{ label: 'Benin', value: 'BJ' },
{ label: 'Bermuda', value: 'BM' },
{ label: 'Bhutan', value: 'BT' },
{ label: 'Bolivia', value: 'BO' },
{ label: 'Bosnia and Herzegovina', value: 'BA' },
{ label: 'Botswana', value: 'BW' },
{ label: 'Bouvet Island', value: 'BV' },
{ label: 'Brazil', value: 'BR' },
{ label: 'British Indian Ocean Territory', value: 'IO' },
{ label: 'Brunei Darussalam', value: 'BN' },
{ label: 'Bulgaria', value: 'BG' },
{ label: 'Burkina Faso', value: 'BF' },
{ label: 'Burundi', value: 'BI' },
{ label: 'Cambodia', value: 'KH' },
{ label: 'Cameroon', value: 'CM' },
{ label: 'Canada', value: 'CA' },
{ label: 'Cape Verde', value: 'CV' },
{ label: 'Cayman Islands', value: 'KY' },
{ label: 'Central African Republic', value: 'CF' },
{ label: 'Chad', value: 'TD' },
{ label: 'Chile', value: 'CL' },
{ label: 'China', value: 'CN' },
{ label: 'Christmas Island', value: 'CX' },
{ label: 'Cocos (Keeling) Islands', value: 'CC' },
{ label: 'Colombia', value: 'CO' },
{ label: 'Comoros', value: 'KM' },
{ label: 'Congo', value: 'CG' },
{ label: 'Congo, The Democratic Republic of the', value: 'CD' },
{ label: 'Cook Islands', value: 'CK' },
{ label: 'Costa Rica', value: 'CR' },
{ label: "Cote D'Ivoire", value: 'CI' },
{ label: 'Croatia', value: 'HR' },
{ label: 'Cuba', value: 'CU' },
{ label: 'Cyprus', value: 'CY' },
{ label: 'Czech Republic', value: 'CZ' },
{ label: 'Denmark', value: 'DK' },
{ label: 'Djibouti', value: 'DJ' },
{ label: 'Dominica', value: 'DM' },
{ label: 'Dominican Republic', value: 'DO' },
{ label: 'Ecuador', value: 'EC' },
{ label: 'Egypt', value: 'EG' },
{ label: 'El Salvador', value: 'SV' },
{ label: 'Equatorial Guinea', value: 'GQ' },
{ label: 'Eritrea', value: 'ER' },
{ label: 'Estonia', value: 'EE' },
{ label: 'Ethiopia', value: 'ET' },
{ label: 'Falkland Islands (Malvinas)', value: 'FK' },
{ label: 'Faroe Islands', value: 'FO' },
{ label: 'Fiji', value: 'FJ' },
{ label: 'Finland', value: 'FI' },
{ label: 'France', value: 'FR' },
{ label: 'French Guiana', value: 'GF' },
{ label: 'French Polynesia', value: 'PF' },
{ label: 'French Southern Territories', value: 'TF' },
{ label: 'Gabon', value: 'GA' },
{ label: 'Gambia', value: 'GM' },
{ label: 'Georgia', value: 'GE' },
{ label: 'Germany', value: 'DE' },
{ label: 'Ghana', value: 'GH' },
{ label: 'Gibraltar', value: 'GI' },
{ label: 'Greece', value: 'GR' },
{ label: 'Greenland', value: 'GL' },
{ label: 'Grenada', value: 'GD' },
{ label: 'Guadeloupe', value: 'GP' },
{ label: 'Guam', value: 'GU' },
{ label: 'Guatemala', value: 'GT' },
{ label: 'Guernsey', value: 'GG' },
{ label: 'Guinea', value: 'GN' },
{ label: 'Guinea-Bissau', value: 'GW' },
{ label: 'Guyana', value: 'GY' },
{ label: 'Haiti', value: 'HT' },
{ label: 'Heard Island and Mcdonald Islands', value: 'HM' },
{ label: 'Holy See (Vatican City State)', value: 'VA' },
{ label: 'Honduras', value: 'HN' },
{ label: 'Hong Kong', value: 'HK' },
{ label: 'Hungary', value: 'HU' },
{ label: 'Iceland', value: 'IS' },
{ label: 'India', value: 'IN' },
{ label: 'Indonesia', value: 'ID' },
{ label: 'Iran, Islamic Republic Of', value: 'IR' },
{ label: 'Iraq', value: 'IQ' },
{ label: 'Ireland', value: 'IE' },
{ label: 'Isle of Man', value: 'IM' },
{ label: 'Israel', value: 'IL' },
{ label: 'Italy', value: 'IT' },
{ label: 'Jamaica', value: 'JM' },
{ label: 'Japan', value: 'JP' },
{ label: 'Jersey', value: 'JE' },
{ label: 'Jordan', value: 'JO' },
{ label: 'Kazakhstan', value: 'KZ' },
{ label: 'Kenya', value: 'KE' },
{ label: 'Kiribati', value: 'KI' },
{ label: "Korea, Democratic People'S Republic of", value: 'KP' },
{ label: 'Korea, Republic of', value: 'KR' },
{ label: 'Kuwait', value: 'KW' },
{ label: 'Kyrgyzstan', value: 'KG' },
{ label: "Lao People'S Democratic Republic", value: 'LA' },
{ label: 'Latvia', value: 'LV' },
{ label: 'Lebanon', value: 'LB' },
{ label: 'Lesotho', value: 'LS' },
{ label: 'Liberia', value: 'LR' },
{ label: 'Libyan Arab Jamahiriya', value: 'LY' },
{ label: 'Liechtenstein', value: 'LI' },
{ label: 'Lithuania', value: 'LT' },
{ label: 'Luxembourg', value: 'LU' },
{ label: 'Macao', value: 'MO' },
{ label: 'Macedonia, The Former Yugoslav Republic of', value: 'MK' },
{ label: 'Madagascar', value: 'MG' },
{ label: 'Malawi', value: 'MW' },
{ label: 'Malaysia', value: 'MY' },
{ label: 'Maldives', value: 'MV' },
{ label: 'Mali', value: 'ML' },
{ label: 'Malta', value: 'MT' },
{ label: 'Marshall Islands', value: 'MH' },
{ label: 'Martinique', value: 'MQ' },
{ label: 'Mauritania', value: 'MR' },
{ label: 'Mauritius', value: 'MU' },
{ label: 'Mayotte', value: 'YT' },
{ label: 'Mexico', value: 'MX' },
{ label: 'Micronesia, Federated States of', value: 'FM' },
{ label: 'Moldova, Republic of', value: 'MD' },
{ label: 'Monaco', value: 'MC' },
{ label: 'Mongolia', value: 'MN' },
{ label: 'Montserrat', value: 'MS' },
{ label: 'Morocco', value: 'MA' },
{ label: 'Mozambique', value: 'MZ' },
{ label: 'Myanmar', value: 'MM' },
{ label: 'Namibia', value: 'NA' },
{ label: 'Nauru', value: 'NR' },
{ label: 'Nepal', value: 'NP' },
{ label: 'Netherlands', value: 'NL' },
{ label: 'Netherlands Antilles', value: 'AN' },
{ label: 'New Caledonia', value: 'NC' },
{ label: 'New Zealand', value: 'NZ' },
{ label: 'Nicaragua', value: 'NI' },
{ label: 'Niger', value: 'NE' },
{ label: 'Nigeria', value: 'NG' },
{ label: 'Niue', value: 'NU' },
{ label: 'Norfolk Island', value: 'NF' },
{ label: 'Northern Mariana Islands', value: 'MP' },
{ label: 'Norway', value: 'NO' },
{ label: 'Oman', value: 'OM' },
{ label: 'Pakistan', value: 'PK' },
{ label: 'Palau', value: 'PW' },
{ label: 'Palestinian Territory, Occupied', value: 'PS' },
{ label: 'Panama', value: 'PA' },
{ label: 'Papua New Guinea', value: 'PG' },
{ label: 'Paraguay', value: 'PY' },
{ label: 'Peru', value: 'PE' },
{ label: 'Philippines', value: 'PH' },
{ label: 'Pitcairn', value: 'PN' },
{ label: 'Poland', value: 'PL' },
{ label: 'Portugal', value: 'PT' },
{ label: 'Puerto Rico', value: 'PR' },
{ label: 'Qatar', value: 'QA' },
{ label: 'Reunion', value: 'RE' },
{ label: 'Romania', value: 'RO' },
{ label: 'Russian Federation', value: 'RU' },
{ label: 'RWANDA', value: 'RW' },
{ label: 'Saint Helena', value: 'SH' },
{ label: 'Saint Kitts and Nevis', value: 'KN' },
{ label: 'Saint Lucia', value: 'LC' },
{ label: 'Saint Pierre and Miquelon', value: 'PM' },
{ label: 'Saint Vincent and the Grenadines', value: 'VC' },
{ label: 'Samoa', value: 'WS' },
{ label: 'San Marino', value: 'SM' },
{ label: 'Sao Tome and Principe', value: 'ST' },
{ label: 'Saudi Arabia', value: 'SA' },
{ label: 'Senegal', value: 'SN' },
{ label: 'Serbia and Montenegro', value: 'CS' },
{ label: 'Seychelles', value: 'SC' },
{ label: 'Sierra Leone', value: 'SL' },
{ label: 'Singapore', value: 'SG' },
{ label: 'Slovakia', value: 'SK' },
{ label: 'Slovenia', value: 'SI' },
{ label: 'Solomon Islands', value: 'SB' },
{ label: 'Somalia', value: 'SO' },
{ label: 'South Africa', value: 'ZA' },
{ label: 'South Georgia and the South Sandwich Islands', value: 'GS' },
{ label: 'Spain', value: 'ES' },
{ label: 'Sri Lanka', value: 'LK' },
{ label: 'Sudan', value: 'SD' },
{ label: 'Surilabel', value: 'SR' },
{ label: 'Svalbard and Jan Mayen', value: 'SJ' },
{ label: 'Swaziland', value: 'SZ' },
{ label: 'Sweden', value: 'SE' },
{ label: 'Switzerland', value: 'CH' },
{ label: 'Syrian Arab Republic', value: 'SY' },
{ label: 'Taiwan, Province of China', value: 'TW' },
{ label: 'Tajikistan', value: 'TJ' },
{ label: 'Tanzania, United Republic of', value: 'TZ' },
{ label: 'Thailand', value: 'TH' },
{ label: 'Timor-Leste', value: 'TL' },
{ label: 'Togo', value: 'TG' },
{ label: 'Tokelau', value: 'TK' },
{ label: 'Tonga', value: 'TO' },
{ label: 'Trinidad and Tobago', value: 'TT' },
{ label: 'Tunisia', value: 'TN' },
{ label: 'Turkey', value: 'TR' },
{ label: 'Turkmenistan', value: 'TM' },
{ label: 'Turks and Caicos Islands', value: 'TC' },
{ label: 'Tuvalu', value: 'TV' },
{ label: 'Uganda', value: 'UG' },
{ label: 'Ukraine', value: 'UA' },
{ label: 'United Arab Emirates', value: 'AE' },
{ label: 'United Kingdom', value: 'GB' },
{ label: 'United States', value: 'US' },
{ label: 'United States Minor Outlying Islands', value: 'UM' },
{ label: 'Uruguay', value: 'UY' },
{ label: 'Uzbekistan', value: 'UZ' },
{ label: 'Vanuatu', value: 'VU' },
{ label: 'Venezuela', value: 'VE' },
{ label: 'Viet Nam', value: 'VN' },
{ label: 'Virgin Islands, British', value: 'VG' },
{ label: 'Virgin Islands, U.S.', value: 'VI' },
{ label: 'Wallis and Futuna', value: 'WF' },
{ label: 'Western Sahara', value: 'EH' },
{ label: 'Yemen', value: 'YE' },
{ label: 'Zambia', value: 'ZM' },
{ label: 'Zimbabwe', value: 'ZW' },
],
[],
);
const fetchOptions = async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(
countriesList.map((country) => ({
...country,
sublabel: country.value,
startIcon: (
<img
loading='lazy'
style={{ width: 20, height: 15 }}
src={`https://flagcdn.com/w20/${country.value.toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${country.value.toLowerCase()}.png 2x`}
alt=''
/>
),
})),
);
}, 2000);
});
};
const [options, setOptions] = React.useState([]);
const [selectedValue, setSelectedValue] = React.useState();
const [isLoading, setIsLoading] = React.useState(true);
const onChange = React.useCallback((value) => {
setSelectedValue(value);
}, []);
const emptyContent = React.useMemo(() => {
return isLoading ? (
<>
{new Array(6).fill(null).map((_, index) => {
return (
<MenuItemSkeleton
key={index}
hasIcon
hasSublabel
contentWidth={`${Math.min(
Math.max(Math.random() * 100, 25),
60,
)}%`}
/>
);
})}
</>
) : (
'No options found'
);
}, [isLoading]);
return (
<ComboBox
inputProps={{ placeholder: 'Select a country' }}
value={selectedValue}
onChange={onChange}
emptyStateMessage={emptyContent}
options={options}
onShow={React.useCallback(async () => {
if (!isLoading) {
return;
}
setOptions(await fetchOptions());
setIsLoading(false);
}, [isLoading])}
/>
);
};
Custom renderer
The property itemRenderer
allows you to customize the combobox more specifically. Note that for keyboard navigation to work, the returned element should use the id
provided by this function. The isFocused
state is calculated using this id
and can be used for specifying the focus styling. If a MenuItem
is returned, then focus styling is automatically handled.
import * as React from 'react';
import { ComboBox, MenuItem } from '@itwin/itwinui-react';
export default () => {
const options = React.useMemo(
() => [
{ label: 'Hour', value: 'hour' },
{ label: 'Day', value: 'day' },
{ label: 'Week', value: 'week' },
{ label: 'Month', value: 'month' },
{ label: 'Year', value: 'year' },
],
[],
);
const [selectedValue, setSelectedValue] = React.useState('');
const onChange = React.useCallback((value) => {
setSelectedValue(value);
}, []);
const itemRenderer = React.useCallback(
({ value, label }, { isSelected, id }) => (
<MenuItem key={id} id={id} isSelected={isSelected} value={value}>
<em
style={{
fontWeight: isSelected ? 'bold' : undefined,
textTransform: 'uppercase',
}}
>
{label}
</em>
</MenuItem>
),
[],
);
return (
<ComboBox
options={options}
inputProps={{ placeholder: 'Select a country' }}
value={selectedValue}
onChange={onChange}
itemRenderer={itemRenderer}
/>
);
};
Props
Prop | Description | Default |
---|---|---|
options | Array of options that populate the dropdown list. SelectOption<T>[] | |
message | Message shown below the combobox.
Use StatusMessage component.ReactNode | |
filterFunction | Function to customize the default filtering logic. (options: SelectOption<T>[], inputValue: string) => SelectOption<T>[] | |
inputProps | Native input element props. Omit<Omit<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & { ...; }, "as" | keyof InputProps> & InputProps & { ...; } | |
dropdownMenuProps | Props to customize dropdown menu behavior. ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement> & Pick<PopoverOptions & { ...; } & Omit<...>, "middleware"> & Pick<...> | |
endIconProps | End icon props. Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ...; }, "as" | keyof ComboBoxEndIconProps> & ComboBoxEndIconProps & { ...; } | |
emptyStateMessage | Message shown when no options are available.
If JSX.Element is provided, it will be rendered as is and won't be wrapped with MenuExtraContent .ReactNode | 'No options found' |
itemRenderer | A custom item renderer can be specified to control the rendering. For keyboard navigation to work, the returned element should use the id provided by this function.
The isFocused state is calculated using this id and can be used for specifying the focus styling.
If a MenuItem is returned, then focus styling is automatically handled.(option: SelectOption<T>, states: { isSelected: boolean; isFocused: boolean; id: string; index: number; }) => Element | |
enableVirtualization | If enabled, virtualization is used for the scrollable dropdown list.
Use it if you expect a very long list of items.
@beta boolean | false |
onShow | Callback fired when dropdown menu is opened. () => void | |
onHide | Callback fired when dropdown menu is closed. () => void | |
multiple | Enable multiple selection. boolean | false |
value | Controlled value of ComboBox.
If multiple is enabled, it is an array of values.Pass null or undefined to reset the value. Apart from resetting the value:
T | T[] | |
defaultValue | Default value of value that is set on initial render. This is useful when you don't want to
maintain your own state but still want to control the initial value .T | T[] | |
onChange | Callback fired when selected value changes. ((value: T) => void) | ((value: T[], event: MultipleOnChangeProps<T>) => void) | |
clearFilterOnOptionToggle | Only applicable when multiple is enabled.If true , toggling an option will clear the filter.
Useful when users would likely want to re-filter after toggling an option.If false , the filter will remain as-is after toggling an option.
Useful when users would likely want to toggle multiple options from the same filtered results.boolean | true |
status | "positive" | "warning" | "negative" | |
id | string | |
className | string | |
style | CSSProperties | |
ref | ForwardedRef<HTMLElement> |