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.
The Magic Behind React-Select
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.
How To Create Custom Options with HTML Templates
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.
Styling the Menu and MenuList: Giving Your Dropdown Some Sass
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. CustomizingmenuList
will affect the styling and layout of the options inside themenu
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.
Let's Jazz Up That Input
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 withoverflow: hidden
set. So, if yourreact-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'soverflow: 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!
The Aha Moment
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! 🚀