React Select Example | React Dropdown Menu - Fully Customizable

In this post you will learn how to implement single select and multi select and customize it inside React.

Finished project

And actually what I want to show you is a library and not a custom implementation. I'm not a fan of using libraries but there are some usecases where it is much easier to use a library than to implement it on your own.

The library that I want to show you is called React-select. This is the most popular library to work with single and multi select inside React. It has an amazing API and is really customizable.

This is why here I want to show you 5 different ways how you can use this library for your everyday needs. To install this library you can write

yarn add react-select

Single select

Now let's look on the first way of usage. This is just a usage of single select with predefined data which are static.

const App = () => {
  const options = [
    { value: "jack", label: "Jack" },
    { value: "john", label: "John" },
    { value: "mike", label: "Mike" },
  ];

  return (
    <h1>Hello monsterlessons</h1>
  );
};

Here we just have options with value and label. This is the format in which React-select accepts data.

Now let's import a single select.

import Select from "react-select";

...

return <Select options={options} />

We just used Select and provided our options inside. This is the bare minimum to use this library.

Single select

As you can see inside browser we are getting a select. It is already customized, styled, we can open it we see our users inside.

But obviously we want to react on user selection in some way and for this we have onChange.

const handleChange = selectedOption => {
  console.log('handleChange', selectedOption)
}
return <Select options={options} onChange={handleChange} />

Now every single time when we select a user we get a callback with our user object.

Multiselect

The next usage that we want to React-select is obviously multiselect. It is extremely easy to add it. We don't need to change anything at all but just provide isMulti.

return <Select options={options} onChange={handleChange} isMulti />

It will directly change the whole single select to multi select.

Multiselect

As you can see it is already changed to milti select. When we select an item we see several selected elements and in our callback we get an array instead of the single object.

Async data

Here is a usecase that you for sure need. It is working with async data. Typically we don't just have static data for a select but we get this data from API and it is fully dynamic.

import AsyncSelect from 'react-select/async'
...
const loadOptions = (searchValue, callback) => {
  setTimeout(() => {
    const filteredOptions = options.filter(option => {
      return option.label.toLowerCase().includes(searchValue.toLowerCase())
    })
    console.log('loadOptions', searchValue, filteredOptions)
    callback(filteredOptions)
  }, 2000)

  ...

  return <AsyncSelect loadOptions={loadOptions} onChange={handleChange} isMulti />
}

Here we used AsyncSelect instead and passed loadOptions function to it. Load options function it designed to get asynchronous data from API by some searchValue. This is why we wrap the code in timeout to simulate long API call and filter our options by searchValue.

To tell select that we are ready with our asynchronous code we must call callback function and provide array of options inside.

As you can see in browser nothing happens by default. Our select is empty. But when we type something in it our loadOptions will happen and after some time we will get data just like from the API..

Async select

But typically you want to load all data on initialize. We can do that by adding one more parameter. And this parameter is called defaultOptions.

return <AsyncSelect loadOptions={loadOptions} onChange={handleChange} isMulti defaultOptions />

Now on initialize after 2 seconds we get all data.

You must keep in mind that if you have a lot of data on backend loading it all without filtering is not the best idea.

Styling select

The next important case that you need in your project is customizing and styling of the select. It is totally possible to do it inside select.

const colorStyles = {
  control: (styles) => ({ ...styles, backgroundColor: "white" })
}

return <Select options={options} onChange={handleChange} styles={colorStyles} />

We can customize different parts of select by providing styles. Here we changed just control property. Inside we pass a function where we get access to all default styles of this elements and can override them.

Now let's do the same with all elements.

const colorStyles = {
  control: (styles) => ({ ...styles, backgroundColor: "white" }),
  option: (styles, { data, isDisabled, isFocused, isSelected }) => {
    return { ...styles, color: data.color };
  },
  multiValue: (styles, { data }) => {
    return {
      ...styles,
      backgroundColor: data.color,
      color: "#fff",
    };
  },
  multiValueLabel: (styles, { data }) => {
    return {
      ...styles,
      color: "#fff",
    };
  },
  multiValueRemove: (styles, { data }) => {
    return {
      ...styles,
      color: "#fff",
      cursor: "pointer",
      ":hover": {
        color: "#fff",
      },
    };
  },
};

We do exactly the same with different properties. As you can see we also have access to data, isDisabled, isFocused, isSelected so we can apply styles for different usecases.

Finished project

Creatable React select

The last case that I want to show you is creatable select. Inside the select we can directly create new options.

import CreatableSelect from "react-select/creatable";

return (
  <CreatableSelect
    options={options}
    onChange={handleChange}
    isMulti
    styles={colorStyles}
  />
);

The whole code stays the same but we use CreatableSelect now. When we type some text we can click on it and this option will be passed in handleChange function.

Bonus

But it is not all. I want to show you 2 callbacks that you can use to react on some changes in select.

const handleChange = (selectedOption, actionMeta) => {
  console.log("handleChange", selectedOption, actionMeta);
};
const handleInputChange = (inputValue, actionMeta) => {
  console.log("handleInputChange", inputValue, actionMeta);
};
return (
  <CreatableSelect
    options={options}
    onChange={handleChange}
    onInputChange={handleInputChange}
    isMulti
    styles={colorStyles}
  />
);

Here we defined onInputChange. Also we added actionMeta to both callbacks. Now if you try to add elements you get different logs about what happens inside a select like focus, blur, select element on which you can react.

Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!

📚 Source code of what we've done
Did you like my post? Share it with friends!
Don't miss a thing!
Follow me on Youtube, Twitter or Instagram.
Oleksandr Kocherhin
Oleksandr Kocherhin is a full-stack developer with a passion for learning and sharing knowledge on Monsterlessons Academy and on his YouTube channel. With around 15 years of programming experience and nearly 9 years of teaching, he has a deep understanding of both disciplines. He believes in learning by doing, a philosophy that is reflected in every course he teaches. He loves exploring new web and mobile technologies, and his courses are designed to give students an edge in the fast-moving tech industry.