Custom option render with react-select and Typescript
I have a react-select
component in a Typescript project that looks like this (notice the component type annotations ♥️):
export type Category = {
label: string;
value: string;
};
const categories = [{ label: 'Option 1', value: '1' }, { label: 'Option 2', value: '2' }]
<Select<Category>
classNamePrefix="my-prefix"
maxMenuHeight={200}
options={categories}
/>;
And I have to change it in order to show a description of each option:
Luckily enough, react-select is ultra customizable.
Option 1: using react-select
components overrides ❌ #
First I thought I have to use a custom render. Something like this:
const OptionWithDescription = ({ children, ...props }) => {
...
};
<Select
options={options}
components=
/>
But replacing components in react select is not a trivial task. Fortunately, there is a much simpler alternative.
Option 2: using formatOptionLabel
✅ #
This function recevies two parameters: the option itself (typed in the component) and some metadata. That metadata has the following type:
export interface FormatOptionLabelMeta<OptionType extends OptionTypeBase> {
context: FormatOptionLabelContext;
inputValue: string;
selectValue: ValueType<OptionType>;
}
export type FormatOptionLabelContext = "menu" | "value";
Add description to Cateogry #
The first to do is add an (optional) description to category:
export type Category = {
label: string;
value: string;
description?: string;
};
Write a custom formatter #
We want to show the description only in menu:
function formatOptionLabel(
category: Category,
meta: FormatOptionLabelMeta<Category>
) {
const showDescription = meta.context === "menu" && category.description;
return showDescription ? (
<div>
<div>{category.label}</div>
<div className={styles["form__select--description"]}>
{category.description}
</div>
</div>
) : (
<div>{category.label}</div>
);
}
And use it:
<Select<Category>
...
formatOptionLabel={formatOptionLabel}
/>