packages/grafana-ui/src/components/Select/Select.mdx
import { ArgTypes } from '@storybook/addon-docs/blocks'; import { Select, AsyncSelect } from './Select';
Select is the base for every component on this page. The approaches mentioned here are also applicable to AsyncSelect, MultiSelect, AsyncMultiSelect.
This component is particularly useful when you have a large number of options to choose from. Additionally, consider using Select in favor of radio button components when you have more than 4 options to choose from.
Select is an input with the ability to search and create new values. It should be used when you have a list of options. If the data has a tree structure, consider using Cascader instead.
Select has some features:
There are four properties for each option:
label - Text that is visible in the menu.value - Could be anything, but is usually a string. Used to identify what is actually selected.description - Longer description that describes the choice. Use this sparingly.imgUrl - URL to an image. Use this when an image or icon provides more context for the option.const options = [
{ label: 'Basic option', value: 0 },
{ label: 'Option with description', value: 1, description: 'this is a description' },
{
label: 'Option with description and image',
value: 2,
description: 'This is a very elaborate description, describing all the wonders in the world.',
imgUrl: 'https://placekitten.com/40/40',
},
];
Creatable option is used when you want to be able to add a custom value to the list of options. allowCustomValue needs to be true and you must handle the value creation with onCreateOption.
import { Select } from "@grafana/ui";
const SelectComponent = () => {
const [value, setValue] = useState<SelectableValue<number>>();
return (
<Select
options={option}
value={value}
allowCustomValue
onCreateOption={customValue => {
setValue(customValue);
}}
/>
);
};
If you want to reset the selected value from outside the component, e.g. if there are two Select components that should be in sync, you can set the dependent Select value to null in the onChange handler of the first Select component.
import { useState } from 'react';
import { Select } from '@grafana/ui';
const SelectComponent = () => {
const [person, setPerson] = useState<string | undefined>('');
const [team, setTeam] = useState<string | undefined | null>('');
return (
<form>
<Select
onChange={({ value }) => {
setPerson(value);
setTeam(null); // Setting the team to null will reset the selected value in the team Select
}}
options={[
{
value: 'option1',
label: 'Option 1',
},
{
value: 'option2',
label: 'Option 2',
},
]}
value={person}
backspaceRemovesValue
/>
<Select
onChange={({ value }) => setTeam(value)}
options={[
{
value: 'team1',
label: 'Team 1',
},
{
value: 'team',
label: 'Team 2',
},
]}
value={team}
/>
</form>
);
};
Like regular Select, but handles fetching options asynchronously. Use the loadOptions prop for the async function that loads the options. If defaultOptions is set to true, loadOptions will be called when the component is mounted.
import { AsyncSelect } from '@grafana/ui';
const basicSelectAsync = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<AsyncSelect
loadOptions={loadAsyncOptions}
defaultOptions
value={value}
onChange={v => {
setValue(v);
}}
/>
);
};
Where the async function could look like this:
const loadAsyncOptions = () => {
return new Promise<Array<SelectableValue<string>>>((resolve) => {
setTimeout(() => {
resolve(options);
}, 2000);
});
};
Possible to Select multiple values at the same time.
import { MultiSelect } from '@grafana/ui';
const multiSelect = () => {
const [value, setValue] = useState<Array<SelectableValue<string>>>([]);
return (
<>
<MultiSelect
options={options}
value={value}
onChange={(v) => {
setValue(v);
}}
/>
</>
);
};
Like MultiSelect but handles data asynchronously with the loadOptions prop.
The Select component can be configured to use a virtualized option list. The virtualized prop must be set to true to enable this behavior. This is useful when you have a large number of options, as it improves performance by only rendering the options that are currently visible in the dropdown.
A custom icon can be added to Select, which will be displayed before the selected value, by using the prefix prop.
<Select options={options} value={value} onChange={setValue} prefix={<Icon name="arrow-down" />} />
Using React Testing Library, you can select the <Select /> using its matching label, such as the label assigned with the inputId prop. Use the react-select-event package to select values from the options.
import { render, screen } from '@testing-library/react';
import selectEvent from 'react-select-event';
import { Select } from '@grafana/ui';
it('should call onChange', () => {
const onChange = jest.fn();
render(
<>
<label htmlFor="my-select">My select</label>
<Select onChange={onChange} options={options} inputId="my-select" />
</>
);
const selectEl = screen.getByLabelText('My select');
expect(selectEl).toBeInTheDocument();
await selectEvent.select(selectEl, 'Option 2', { container: document.body });
expect(onChange).toHaveBeenCalledWith({
label: 'Option 2',
value: 2,
});
});