Customizing React-Select with TypeScript: A Developer’s Alchemy

Search for a command to run...

No comments yet. Be the first to comment.
~10× less output, ~3× faster, measured. Plus the second lever — history compaction — that cuts multi-turn input ~60%.

And to improve your code

So I made a cheat sheet in plain english

A step-by-step guide

Today we deploy a website on our own server

If you're reading this article because you think customizing the react-select library with TypeScript is going to be a walk in the park—close this tab right now. After combing through the documentation, I, too, was under the impression that this would be a plug-and-play endeavor. Man, was I in for a surprise!
Still here? Cool, let's dive right in.
For those who don't know, react-select is a highly customizable replacement for the HTML <select> element. It works exceptionally well with React, providing numerous ways to style the dropdown and the options within.
Before diving into the code, let's understand that react-select gives you a very nifty components prop. This allows you to override any part of the UI.
Here's a quick example:
import React from 'react';
import Select, { components } from 'react-select';
const CustomOption = (props: any) => (
<components.Option {...props}>
<div>
<strong>{props.data.label}</strong>
<small>{props.data.description}</small>
</div>
</components.Option>
);
export const MySelect = () => (
<Select
components={{ Option: CustomOption }}
options={[
{ label: 'Apple', value: 'apple', description: 'A red fruit' },
{ label: 'Banana', value: 'banana', description: 'A yellow fruit' }
]}
/>
);
If you want to add more finesse to your options, you can use the isDisabled, isFocused, isSelected props.
import React from 'react';
import Select, { components } from 'react-select';
const CustomOption = (props: any) => {
const { isDisabled, isFocused, isSelected } = props;
return (
<components.Option {...props}>
<div style={{ opacity: isDisabled ? 0.5 : 1 }}>
<strong>{props.data.label}</strong>
{ isSelected && <span> •</span> }
<small style={{ color: isFocused ? 'blue' : 'grey' }}>
{props.data.description}
</small>
</div>
</components.Option>
);
};
export const MySelect = () => (
<Select
components={{ Option: CustomOption }}
options={[
{ label: 'Apple', value: 'apple', description: 'A red fruit' },
{ label: 'Banana', value: 'banana', description: 'A yellow fruit' }
]}
/>
);
Now you can make that option look the way you want.
So you know:
the menu: is essentially the container that wraps around all the options you see when the dropdown is activated. It is responsible for the placement, size, and other container-specific styling of the dropdown list. Customizing menu will affect the dropdown's outer box.
the menuList: is a child component within the menu and directly wraps around the individual option items. Customizing menuList will affect the styling and layout of the options inside the menu but not the external container itself.
Think of menu as the outer shell and menuList as the inner lining. Any customization you apply to these components will alter how the dropdown appears and behaves when opened.
Customizing the style in react-select is made possible with the styles prop. You can easily change the border radius, color, and many other styles.
const customStyles = {
menu: (provided: any) => ({
...provided,
borderRadius: '0px',
backgroundColor: 'lightgray'
}),
menuList: (provided: any) => ({
...provided,
padding: '0px'
})
};
export const MyStyledSelect = () => (
<Select
styles={customStyles}
options={[
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' }
]}
/>
);
Just remember that some of the styles might need an !important next to them or else they won't show.
The input box itself can also be styled, just like the menu and options. Simply target control in the styles prop.
const inputStyles = {
control: (provided: any) => ({
...provided,
borderRadius: '15px',
borderColor: '#3f51b5'
})
};
export const MyInputStyledSelect = () => (
<Select
styles={inputStyles}
options={[
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' }
]}
/>
);
Don't forget about the menuPosition
The menuPosition is another vital setting when you're customizing your dropdowns, and it's often mistaken for menuPlacement. While menuPlacement determines the location of the menu in terms of above or below the control, menuPosition goes further to dictate how the dropdown menu is positioned in the DOM.
Here are the options you can set for the menuPosition prop:
absolute: This is the default value. The menu is rendered within the DOM hierarchy of the control. It won't break out of a parent element with overflow: hidden set. So, if your react-select component is inside a container that hides overflow, the dropdown might not be displayed properly.
fixed: The menu is rendered at the root level of the DOM hierarchy, so it's not constrained by a parent's overflow: hidden style. This setting allows the dropdown to break out of any containing element, ensuring visibility.
Here's how you'd set it in code:
import Select from 'react-select';
export const MyFixedMenuSelect = () => (
<Select
menuPosition="fixed"
options={[
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' }
]}
/>
);
In this example, by setting the menuPosition to "fixed", the dropdown will be appended to the root level of the DOM and will not be confined by a parent element with overflow: hidden.
Think of menuPosition as the setup for how your dropdown behaves in a broader context within the DOM, much like how middleware affects an entire application. It gives you the control to adapt your dropdown menu to various scenarios and layout constraints. Choose wisely based on your application's needs!
By now, you should be feeling pretty comfortable manipulating react-select with TypeScript.
The best part? You can have these complex styles and custom options up and running faster than you can say "JavaScript fatigue."
That’s all, folks.
Happy coding! 🚀