Select Component in React

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Select Component in React

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Select Component Browser Basics

To create a Select component (also called Combo Box / List Box / Drop Down in UX / Software Development) we use the select, option and label html tags.

This is demonstrated below where we don't use React and just provide and render a browser controlled component.

App.tsx
export default function App() {
return (
<>
<label htmlFor="pet">Choose a pet</label>
<select id="pet">
<option value="dog">Dog</option>
<option value="cat">Cat</option>
<option value="parrot">Parrot</option>
<option value="chicken">Chicken</option>
</select>
</>
);
}

Some additional user tips:

  • You can click on the label to focus the select thanks to the id linking
  • You can navigate the select with the space-bar and arrow keys

Controlled Select component with React

We can wire the select to a state so that it is controlled by React. For this purpose we use the select.value and select.onChange props.

This is demonstrated below.

App.tsx
import { useState } from 'react';

export default function App() {
/** Create a state variable to store the selected value */
const [value, setValue] = useState('dog');

return (
<>
<label htmlFor="pet">Choose a pet</label>
{/* Wire the `value` and `onChange` props */}
<select id="pet" value={value} onChange={(e) => setValue(e.target.value)}>
<option value="dog">Dog</option>
<option value="cat">Cat</option>
<option value="parrot">Parrot</option>
<option value="chicken">Chicken</option>
</select>
{/* Display an icon based on the selected value */}
{{
'dog': '🐕',
'cat': '🐈',
'parrot': '🦜',
'chicken': '🐓'
}[value]}
</>
);
}

Making a Select Optional

For an optional select we recommend using an option with dedicated display string but an empty string ('') as its value.

This is demonstrated below.

App.tsx
import { useState } from "react";

export default function App() {
/** Start off with an empty value */
const [value, setValue] = useState("");

return (
<>
<label htmlFor="pet">Choose a pet</label>
<select id="pet" value={value} onChange={(e) => setValue(e.target.value)}>
{/* Something to display for an empty value */}
<option value="">None</option>
<option value="dog">Dog</option>
<option value="cat">Cat</option>
<option value="parrot">Parrot</option>
<option value="chicken">Chicken</option>
</select>

{{
'dog': '🐕',
'cat': '🐈',
'parrot': '🦜',
'chicken': '🐓'
}[value]}
</>
);
}

Creating a custom component

Creating a custom component for a select is very similar to what we did for a radio group.

An example custom component is demonstrated below in Select.tsx. Note this our custom Select has a few advanced features baked in:

  • We sort the inputs and cache the sorting with the useMemo hook.
  • When sorting we keep the option with the empty value ('') on top.
  • We ensure that the select can be reused multiple times on the same document by utilising the useId hook.
Select.tsx
App.tsx
import { useId, useMemo } from 'react';

export type SelectProps = {
label: string,
value: string,
onChange: (value: string) => void,
options: { value: string, label: string }[],
};

export const Select = ({ label, value, onChange, options }: SelectProps) => {
const id = useId();
const ordered = useMemo(
() => [...options].sort((a, b) => a.value === '' ? -1 : a.label.localeCompare(b.label)),
[options]
);
return (
<div>
<label htmlFor={id}>{label}</label>
<select id={id} value={value} onChange={e => onChange(e.target.value)}>
{ordered.map(option => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
};
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Continuing our journey into form fields with React. One of the harder core components that I've seen people struggle with is the select component. So in this lesson, we will present it so simply that you'll not be nervous about using it at all. So let's go. We start off with an empty app component and let's just try to use the process, select natively without thinking too much about React. Now to actually build a combo box within the browser, you actually need to use two elements, a select element that has a number of child option elements, each with their own unique value and a display label.

00:33

And that's the heart of the combo box component. You can see that we have the select with the different options being displayed by the browser. Now just like all the other form fields that we've looked at, it is always a good idea to add a label to the select field and associated it with the select. The way we do that is we use the label element at an HTML four attribute and we point it to a value that we will use as a ID on the select element. And with this simple change in place, we have a nice label before the select element to guide the user towards what we want them to do.

01:06

And of course, because of that HTML four and the associated ID props, the user can click on the label and the browser will automatically focus the associated select. There are some other accessibility features built into the select component as well. You can press the space bar to open up the combo box and then use the arrow keys to scroll between them and then press the enter key to select an individual value. Now that we know how the browser select works, let's convert it into a control component by managing its state with React. All that we need to do really to manage the state

01:38

of a select component is to provide a value for the select element. We initialize a value to dog using a simple call to use state. And now for our select element, we provide in the value as well as an on change where we will listen to the event and then update the value to event target value. This is very similar to how you would do it with a standard input element. Just to prove that this component is being completely managed by React and modifying. It does indeed modify the JavaScript value string. Let's just display a different emoji for the different values that the user can select.

02:12

And now if we jump to the ui, you can see that the dog is selected and the emoji for dog is being displayed. If we initialize to a different value, for example, cat, then not only does the select display the cat, but also the emoji cat is being displayed. And of course the user can modify this value by interacting with the input and when the user does, so the on change will get called and we will update the value to the new thing. So if the select a chicken, we get a nice chicken emoji. Now of course, you might want to use the select with an optional member or start without an option selected. And for that we recommend that you use a special option

02:46

that still has a label but only an empty string as its value. And then start the state with an empty string. To demonstrate that, let's just modify our initial call to use state to be an empty string. And then Within the options of the select, we add a new option with the value pointing to an empty string and then a display string that makes sense for the user. For example, please choose an option. And now if you look at the ui, it starts off with a nice empty option, please choose an option, and of course the user can then go ahead and select an option that makes sense for them.

03:19

The text that we have chosen for an empty value definitely makes it feel like a required field because it's going to prompt the user. Please choose an option, but if you want the user to basically select that and opt out, then we can provide a nicer text, for example, none. And now when the user visits the ui, they get an option to select none or a pet of their choosing. Now that we understand the basics of using the select component with React, let's make our lives easier by wrapping it up into a nice reusable utility component. We will create a component in a new file called selector TSX.

03:51

And since we've already seen the use ID hook in a previous lesson, we will use that to create the association between the label and the select. With that HTM four and the ID props, the props for our select component are going to be pretty self-explanatory. We have a root level label and then we have a value of type string and an on change that accepts the updated value. And finally, we have an array of options each with their own unique value and labels within our select component. We simply destructure these props from the past in parameter within the body of the select,

04:23

we create a new ID using use id. And then when we are rendering our component, we will have a root label diviv with the label pointing to the ID and a select pointing to the id, and of course the value and on change for the select element as well. Now, as we have seen the select needs to have different option elements as children, and for that we simply loop through the provided options and then render them out into different option elements for the key required. By React loops, we use option, not value. For value, we use option not value, and of course we use option not label

04:56

as a child of the option element. And that's pretty much all that we need to create a quite reusable select component. Now let's jump into our application component and try to use it. We bring in the select from the select module and then render it out within the app component. Of course, we will have to provide the required props, which is the label, the value, the own change, and the array of options. And that's pretty much it. The state is being managed with U State within the app, and we are passing in the value and set value as the value and on change props to the select component.

05:30

And there we have it a perfectly reusable select component. And the user can select the different options that they want, and it behaves exactly as we have seen before. It is conventional to sort the values in a select to make it easier for the user to find a particular value. So let's add that feature to our custom select component. This is one of the beauties of creating your own custom component. You can add additional functionality without having to repeat it again and again. Now, of course, we want to sort the options that are passed In, and as we've already seen the use memo hook, that is what we will use to make sure that

06:01

that calculation doesn't happen over and over on every render of the select. Within the rendering of the select component, we will use Memo to sort the past in options and the sorting will happen such that if a value is an empty string, then of course this is the empty option and it should be first. And to indicate that this takes precedence, we return minus one irrespective of the second value. Otherwise, we simply compare the labels of A and B to see which one should come first. And for the second argument for use memo, we pass an A dependency array for options.

06:35

So if the options ever change, we need to recalculate the ordered result. The one final change that we need to make is in the rendering of our component, we replace options with ordered options, and that's pretty much it. We can see it in action in our application. The empty value option is on top, and the remaining options are alphabetically ordered based on their label. The rest of the functionality is going to be the same. And just to drive home the point that this is all going to work, let's just move the default one a bit down. And you can see dog is coming before CAT within the code, but within the rendering, the default is on top,

07:09

cat is on top, and everything just works. And that's the basics of using the select component in React. Thank you for joining me and I'll see you in the next one.