← Back
react react-select typescript

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:

custom options

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}
/>