Please Provide the Following Information

The resource you requested will be sent via email.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Please Provide the Following Information

The resource you requested will be sent via email.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Please Provide the Following Information

The resource you requested will be sent via email.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Please Provide the Following Information

The resource you requested will be sent via email.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Blogs
August 9, 2021

Optimize your react-select component to smoothly render 10k+ data

React-select is one of the most popular libraries for dropdown components. It offers solid rendering and filtering for hundreds of options, but when you start to reach about a thousand or so items, you can start to feel a bit of a lag while scrolling through the options and filtering through them.

Below I have created a select dropdown with react-select and populated 5000 dropdown items. You can see that the whole scroll and search experience is very slow and choppy.

Let's look into a couple of different ways of how to improve the performance of this react-select component.

1. Set ignoreAccents to false

React-select, by default, is set to ignore accents like diacritic acute (á), grave (à), and more in the options and search keywords. So every time you type any letter to search through the select options, it calls a function called stripDiacritics for each option twice; once on the provided keyword and once on the option to strip the accent out to check for the match. (Refer to this for reference.) This means, if there are one thousand options, every time you type in a character to search, the function is invoked two thousand times. This obviously impacts the performance for a large number of options in a significant way.

It’s most likely that we don’t need to care for the accents and can in fact turn it off using the following the filterOption prop value.

import ReactSelect, { createFilter } from 'react-select'; <ReactSelect filterOption={createFilter({ ignoreAccents: false })} ... />

Let's save the change and try to filter the dropdown options.

You can see some amount of performance improvement with this on the search filter. It's a good start but there is still more room for improvements. The scrolling still feels extremely laggy.

2. Disable onMouseMove and onMouseOver events

Next, we can improve the performance of the select dropdown by disabling the onMouseMove and onMouseOver events. For that, you will need to create a custom Option component.

import React, { PropTypes } from 'react'; import { components } from 'react-select'; const CustomOption = ({ children, ...props }) => { // eslint-disable-next-line no-unused-vars const { onMouseMove, onMouseOver, ...rest } = props.innerProps; const newProps = { ...props, innerProps: rest }; return ( <components.Option {...newProps}> {children} </components.Option> ); }; CustomOption.propTypes = { innerProps: PropTypes.object.isRequired, children: PropTypes.node.isRequired }; export default CustomOption;

In this component, we have just removed “onMouseMove” and “onMouseOver” properties from innerProps and passed it down to the component.Option. We can then plug the custom component as seen below.

<ReactSelect ... components={{ Option: CustomOption }} />

As you might have noticed, the scroll is now very smooth but the downside is that the background color of the options are no longer changed when hovered and selected. It’s actually easy to fix via css. We first need to add a custom css class to our option.

// our CustomOption component ... const CustomOption = ({ children, ...props }) => { ... return ( <components.Option {...newProps} className="custom-option" > {children} </components.Option> ); } ... <ReactSelect ... classNamePrefix="custom-select" components={{ Option: CustomOption }} />

We can target our custom option with the ‘custom-option’ class now. We have also added a classname prefix to our react-select component. Now let’s bring back the hover and select feedback.

.custom-option { transition: background 60ms; } .custom-option:hover { transition-delay: 60ms; background: #deebff; } .custom-option.custom-select__option--is-focused { background: none; } .custom-option.custom-select__option--is-selected { background: #2684FF; }

We added background color on hover and then removed the default background color for ‘is-focused’ state and overwrote it with background for ‘is-selected’ state. To make everything feel a bit smoother, we have also added transition and transition-delay.

Our dropdown feels extremely smooth now at 5000 data. Let's take it even one step further so that we can achieve this level of performance with 10K+ data.

3. Virtualization

Virtualization is one of the techniques that can help improve the performance of any list component. If you are not familiar with the concept of virtualization, it involves rendering only those items that are currently visible. As the user scrolls through the list, more items are appended/removed at the top and bottom to give the illusion on one continuous list. There is no point in rendering ten thousand items in a list if the user is only going to see ten items at a single instance.

Let’s leverage the power of virtualization into our react-select component. We will be using react-tiny-virtual-list as it has a really small footprint (3.7 kB minified + gzipped). Let’s first look at the syntax of react-tiny-virtual-list.

So it is actually very simple to render a list of a large number of items as a virtual list with this library. Now, just like we created a CustomOption, we need to create a CustomMenuList component that allows us to have control over how we render the elements.

We get the childrenOptions sent to us by react-select and feed it to the VirtualList component. In the ‘renderItem’ function, we also check to see if children are of type Array which indicates that it is trying to render the item from list but if not, we know that it is trying to render the “noOptionsMessage” if no options are available. If we don’t do this, it will display an empty box when there is no match.

Also, let’s add a bit of css to tidy the dropdown option and no options message placeholder.

.react-virtualized-menu-placeholder { margin-top: 12px; color: #9a9a9a; text-align: center; } .react-virtualized-list-wrapper li { list-style: none; }

Finally, you can plug this in just like we did the CustomOption component. Also, make sure to turn off “captureMenuScroll” for the scrolling to work correctly with the virtualized list.

<ReactSelect ... captureMenuScroll={false} classNamePrefix="custom-select" components={{ Option: CustomOption, MenuList: CustomMenuList }} />

Finally, this is how our select dropdown looks like at 10K data with virtualization added.

There you have it. Those were some of the ways to improve the performance of your react-select component in order to handle more than 10K items in the list. If you are looking to handle even more data than that, you should really look into loading the data asynchronously.

Thank you for reading this blog. If you liked it, do checkout our other blogs and articles from Botsplash as well.

To learn more about Botsplash click the button below to schedule a demo with our team.

React-select is one of the most popular libraries for dropdown components. It offers solid rendering and filtering for hundreds of options, but when you start to reach about a thousand or so items, you can start to feel a bit of a lag while scrolling through the options and filtering through them.

Below I have created a select dropdown with react-select and populated 5000 dropdown items. You can see that the whole scroll and search experience is very slow and choppy.

Let's look into a couple of different ways of how to improve the performance of this react-select component.

1. Set ignoreAccents to false

React-select, by default, is set to ignore accents like diacritic acute (á), grave (à), and more in the options and search keywords. So every time you type any letter to search through the select options, it calls a function called stripDiacritics for each option twice; once on the provided keyword and once on the option to strip the accent out to check for the match. (Refer to this for reference.) This means, if there are one thousand options, every time you type in a character to search, the function is invoked two thousand times. This obviously impacts the performance for a large number of options in a significant way.

It’s most likely that we don’t need to care for the accents and can in fact turn it off using the following the filterOption prop value.

import ReactSelect, { createFilter } from 'react-select'; <ReactSelect filterOption={createFilter({ ignoreAccents: false })} ... />

Let's save the change and try to filter the dropdown options.

You can see some amount of performance improvement with this on the search filter. It's a good start but there is still more room for improvements. The scrolling still feels extremely laggy.

2. Disable onMouseMove and onMouseOver events

Next, we can improve the performance of the select dropdown by disabling the onMouseMove and onMouseOver events. For that, you will need to create a custom Option component.

import React, { PropTypes } from 'react'; import { components } from 'react-select'; const CustomOption = ({ children, ...props }) => { // eslint-disable-next-line no-unused-vars const { onMouseMove, onMouseOver, ...rest } = props.innerProps; const newProps = { ...props, innerProps: rest }; return ( <components.Option {...newProps}> {children} </components.Option> ); }; CustomOption.propTypes = { innerProps: PropTypes.object.isRequired, children: PropTypes.node.isRequired }; export default CustomOption;

In this component, we have just removed “onMouseMove” and “onMouseOver” properties from innerProps and passed it down to the component.Option. We can then plug the custom component as seen below.

<ReactSelect ... components={{ Option: CustomOption }} />

As you might have noticed, the scroll is now very smooth but the downside is that the background color of the options are no longer changed when hovered and selected. It’s actually easy to fix via css. We first need to add a custom css class to our option.

// our CustomOption component ... const CustomOption = ({ children, ...props }) => { ... return ( <components.Option {...newProps} className="custom-option" > {children} </components.Option> ); } ... <ReactSelect ... classNamePrefix="custom-select" components={{ Option: CustomOption }} />

We can target our custom option with the ‘custom-option’ class now. We have also added a classname prefix to our react-select component. Now let’s bring back the hover and select feedback.

.custom-option { transition: background 60ms; } .custom-option:hover { transition-delay: 60ms; background: #deebff; } .custom-option.custom-select__option--is-focused { background: none; } .custom-option.custom-select__option--is-selected { background: #2684FF; }

We added background color on hover and then removed the default background color for ‘is-focused’ state and overwrote it with background for ‘is-selected’ state. To make everything feel a bit smoother, we have also added transition and transition-delay.

Our dropdown feels extremely smooth now at 5000 data. Let's take it even one step further so that we can achieve this level of performance with 10K+ data.

3. Virtualization

Virtualization is one of the techniques that can help improve the performance of any list component. If you are not familiar with the concept of virtualization, it involves rendering only those items that are currently visible. As the user scrolls through the list, more items are appended/removed at the top and bottom to give the illusion on one continuous list. There is no point in rendering ten thousand items in a list if the user is only going to see ten items at a single instance.

Let’s leverage the power of virtualization into our react-select component. We will be using react-tiny-virtual-list as it has a really small footprint (3.7 kB minified + gzipped). Let’s first look at the syntax of react-tiny-virtual-list.

So it is actually very simple to render a list of a large number of items as a virtual list with this library. Now, just like we created a CustomOption, we need to create a CustomMenuList component that allows us to have control over how we render the elements.

We get the childrenOptions sent to us by react-select and feed it to the VirtualList component. In the ‘renderItem’ function, we also check to see if children are of type Array which indicates that it is trying to render the item from list but if not, we know that it is trying to render the “noOptionsMessage” if no options are available. If we don’t do this, it will display an empty box when there is no match.

Also, let’s add a bit of css to tidy the dropdown option and no options message placeholder.

.react-virtualized-menu-placeholder { margin-top: 12px; color: #9a9a9a; text-align: center; } .react-virtualized-list-wrapper li { list-style: none; }

Finally, you can plug this in just like we did the CustomOption component. Also, make sure to turn off “captureMenuScroll” for the scrolling to work correctly with the virtualized list.

<ReactSelect ... captureMenuScroll={false} classNamePrefix="custom-select" components={{ Option: CustomOption, MenuList: CustomMenuList }} />

Finally, this is how our select dropdown looks like at 10K data with virtualization added.

There you have it. Those were some of the ways to improve the performance of your react-select component in order to handle more than 10K items in the list. If you are looking to handle even more data than that, you should really look into loading the data asynchronously.

Thank you for reading this blog. If you liked it, do checkout our other blogs and articles from Botsplash as well.

Subscribe to our newsletter... we promise no spam

Botsplash Logo
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.