Multi Select

Multi select is the field type that allows writing text to create “tags” that are represented in the shape of labels.

installyarn add @clayui/multi-select
versionNPM Version
useimport MultiSelect from '@clayui/multi-select';

Multi Select is an aggregate component of the @clayui/form package, consisting of a high-level written above a <ClayInput /> that provides the ability to create tags.

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			label: 'one',
			value: '1',
		},
	]);

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<MultiSelect
					inputName="myInput"
					items={items}
					onChange={setValue}
					onItemsChange={setItems}
					value={value}
				/>
			</div>
		</Provider>
	);
}

Composing

<ClayMultiSelect /> enables you to make compositions to achieve your expected results, as this component is distributed only in a low level component, this increases flexibility and you can create many possibilities but it comes with a price tag… you may want to get close to the Lexicon specifications and will have to compose with some of the other components to get there, let’s detail it further below.

Autocomplete

Usually a MultiSelect has an autocomplete to help the user choose existing tags. You can use the sourceItems API to achieve this result.

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			label: 'one',
			value: '1',
		},
	]);

	const sourceItems = [
		{
			label: 'one',
			value: '1',
		},
		{
			label: 'two',
			value: '2',
		},
		{
			label: 'three',
			value: '3',
		},
		{
			label: 'four',
			value: '4',
		},
	];

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<MultiSelect
					inputName="myInput"
					items={items}
					onChange={setValue}
					onItemsChange={setItems}
					sourceItems={sourceItems}
					value={value}
				/>
			</div>
		</Provider>
	);
}

Select Button

According to the Lexicon specification a Select button can be grouped with MultiSelect to allow tag data to come from elsewhere. You can achieve this result by composing with <ClayForm.Group />, <ClayInput.GroupItem /> and <ClayButton /> .

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import ClayForm, {ClayInput} from '@clayui/form';
import Button from '@clayui/button';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			label: 'one',
			value: '1',
		},
	]);

	const sourceItems = [
		{
			label: 'one',
			value: '1',
		},
		{
			label: 'two',
			value: '2',
		},
		{
			label: 'three',
			value: '3',
		},
		{
			label: 'four',
			value: '4',
		},
	];

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<ClayForm.Group>
					<ClayInput.Group>
						<ClayInput.GroupItem>
							<MultiSelect
								inputName="myInput"
								items={items}
								onChange={setValue}
								onItemsChange={setItems}
								sourceItems={sourceItems}
								value={value}
							/>
						</ClayInput.GroupItem>
						<ClayInput.GroupItem shrink>
							<Button
								displayType="secondary"
								onClick={() => alert('Click')}
							>
								{'Select'}
							</Button>
						</ClayInput.GroupItem>
					</ClayInput.Group>
				</ClayForm.Group>
			</div>
		</Provider>
	);
}

Validation

An input needs validation so you can add some composition props with <ClayInput /> and <ClayForm /> to get the result.

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import ClayForm, {ClayInput} from '@clayui/form';
import Button from '@clayui/button';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			label: 'one',
			value: '1',
		},
	]);

	const sourceItems = [
		{
			label: 'one',
			value: '1',
		},
		{
			label: 'two',
			value: '2',
		},
		{
			label: 'three',
			value: '3',
		},
		{
			label: 'four',
			value: '4',
		},
	];

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<ClayForm.Group className="has-error">
					<label>{'MultiSelect'}</label>

					<ClayInput.Group>
						<ClayInput.GroupItem>
							<MultiSelect
								inputName="myInput"
								items={items}
								onChange={setValue}
								onItemsChange={setItems}
								sourceItems={sourceItems}
								value={value}
							/>

							<ClayForm.FeedbackGroup>
								<ClayForm.FeedbackItem>
									<ClayForm.FeedbackIndicator symbol="info-circle" />

									{'You made an error'}
								</ClayForm.FeedbackItem>
							</ClayForm.FeedbackGroup>
						</ClayInput.GroupItem>
						<ClayInput.GroupItem shrink>
							<Button
								displayType="secondary"
								onClick={() => alert('Click')}
							>
								{'Select'}
							</Button>
						</ClayInput.GroupItem>
					</ClayInput.Group>
				</ClayForm.Group>
			</div>
		</Provider>
	);
}

Custom Autocomplete

To customize Autocomplete content to stylize to your needs and also have filter control, you can use the menuRenderer API.

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import Sticker from '@clayui/sticker';
import Icon from '@clayui/icon';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			email: 'one@example.com',
			label: 'One',
			value: '1',
		},
	]);

	const sourceItems = [
		{
			email: 'one@example.com',
			label: 'One',
			value: '1',
		},
		{
			email: 'two@example.com',
			label: 'Two',
			value: '2',
		},
	];

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<MultiSelect
					inputName="myInput"
					items={items}
					onChange={setValue}
					onItemsChange={setItems}
					sourceItems={sourceItems}
					value={value}
				>
					{(item) => (
						<MultiSelect.Item
							key={item.value}
							textValue={item.label}
						>
							<div className="autofit-row autofit-row-center">
								<div className="autofit-col mr-3">
									<Sticker
										className="sticker-user-icon"
										size="lg"
									>
										<Icon symbol="user" />
									</Sticker>
								</div>
								<div className="autofit-col">
									<strong>{item.label}</strong>
									<span>{item.email}</span>
								</div>
							</div>
						</MultiSelect.Item>
					)}
				</MultiSelect>
			</div>
		</Provider>
	);
}

Sizes

The size property on ClayMultiSelect only modifies the size of the input.

Small

Render a smaller ClayMultiSelect input by setting the size property to sm.

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			label: 'one',
			value: '1',
		},
	]);

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<MultiSelect
					inputName="multiSelectSmallInput"
					items={items}
					onChange={setValue}
					onItemsChange={setItems}
					size="sm"
					value={value}
				/>
			</div>
		</Provider>
	);
}

ClayMultiSelect’s with the Select Button should use the modifier class input-group-sm on input-group or form-group-sm on form-group.

import {Provider} from '@clayui/core';
import MultiSelect from '@clayui/multi-select';
import ClayForm, {ClayInput} from '@clayui/form';
import Button from '@clayui/button';
import React, {useState} from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [value, setValue] = useState('');
	const [items, setItems] = useState([
		{
			label: 'one',
			value: '1',
		},
	]);

	const sourceItems = [
		{
			label: 'one',
			value: '1',
		},
		{
			label: 'two',
			value: '2',
		},
		{
			label: 'three',
			value: '3',
		},
		{
			label: 'four',
			value: '4',
		},
	];

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<ClayForm.Group>
					<ClayInput.Group className="input-group-sm">
						<ClayInput.GroupItem>
							<MultiSelect
								inputName="myInput"
								items={items}
								onChange={setValue}
								onItemsChange={setItems}
								sourceItems={sourceItems}
								value={value}
							/>
						</ClayInput.GroupItem>
						<ClayInput.GroupItem shrink>
							<Button
								displayType="secondary"
								onClick={() => alert('Click')}
							>
								{'Select'}
							</Button>
						</ClayInput.GroupItem>
					</ClayInput.Group>
				</ClayForm.Group>
			</div>
		</Provider>
	);
}

API Reference

itemLabelFilter

(items: Array<Item>, _value: string, _locator?: string) => Array<Item>

Utility used for filtering an array of items based off the locator which is set to label by default.

Parameters

items *

Array<Item>

_value *

string

_locator *

string= "label"
Returns
Item[]

MultiSelect

IForwardRef<HTMLInputElement, IProps<Record<string, any>>>
Parameters
Properties

active

boolean | undefined

Flag to indicate if menu is showing or not.

allowsCustomLabel

boolean | undefined

Whether MultiSelect allows an input value not corresponding to an item to be added.

alignmentByViewport

boolean | undefined

Flag to align the Autocomplete within the viewport.

clearAllTitle

string | undefined

Title for the Clear All button.

closeButtonAriaLabel

string | undefined

Aria label for the Close button of the labels.

defaultActive

boolean | undefined

The initial value of the active state (uncontrolled).

defaultValue

string | undefined

Property to set the default value (uncontrolled).

defaultItems

Array<Record<string, any>> | undefined

Set the default value of label items (uncontrolled).

direction

"bottom" | "top" | undefined

Direction the menu will render relative to the Autocomplete.

menuRenderer

MenuRenderer | undefined

Adds a component to replace the default component that renders the content of the <ClayDropDown /> component.

disabled

boolean | undefined

Flag that indicates to disable all features of the component.

disabledClearAll

boolean | undefined

Flag to disabled Clear All functionality.

hotkeysDescription

string | undefined

Defines the description of hotkeys for the component, use this to handle internationalization.

inputName

string | undefined

Value used for each selected item's hidden input name attribute

inputValue

string | undefined

Value of input

isLoading

boolean | undefined

Flag to indicate if loading icon should be rendered

isValid

boolean | undefined

Flag to indicate if input is valid or not

items

Array<Record<string, any>> | undefined

Values that display as label items (controlled).

liveRegion

{ added: string; removed: string; } | undefined

The off-screen live region informs screen reader users the result of removing or adding a label.

locator

Locator | undefined

Sets the name of the field to map the value/label of the item

messages

{ listCount?: string; listCountPlural?: string; loading: string; notFound: string; hotkeys: string; labelAdded: string; labelRemoved: string; } | undefined

Messages for autocomplete.

onActiveChange

any

Callback for when the active state changes (controlled).

onClearAllButtonClick

(() => void) | undefined

Callback for when the clear all button is clicked

onChange

any

Callback for when the input value changes (controlled).

onItemsChange

any

Callback for when items are added or removed (controlled).

onLoadMore

(() => Promise<any> | null) | undefined

Callback is called when more items need to be loaded when the scroll reaches the bottom.

size

Size | undefined

Determines the size of the Multi Select component.

sourceItems

Array<Record<string, any>> | null | undefined

List of pre-populated items that will show up in a dropdown menu

spritemap

string | undefined

Path to spritemap for clay icons

value

string | undefined

The value property sets the current value (controlled).

loadingState

number | undefined

The current state of Autocomplete current loading. Determines whether the loading indicator should be shown or not.

Returns
ReactElement<any, string | JSXElementConstructor<any>> | null

Item

React.ForwardRefExoticComponent<IProps & React.RefAttributes<HTMLLIElement>>
Parameters
Properties

active

boolean | undefined

Flag that indicates if item is selected.

disabled

boolean | undefined

Flag that indicates if item is disabled or not.

href

string | undefined

Path for item to link to.

roleItem

string | undefined

Sets the role accessibility property of the item. Set the item's container (

  • ) role use the role="" prop instead of roleItem="".

    spritemap

    string | undefined

    Path to icon spritemap from clay-css.

    symbolLeft

    string | undefined

    Flag that indicates if there is an icon symbol on the left side.

    symbolRight

    string | undefined

    Flag that indicates if there is an icon symbol on the right side.

    children

    React.ReactNode

    The item content.

    innerRef

    React.Ref<HTMLAnchorElement> | undefined

    match

    string | undefined

    Match is the string that will be compared with value.

    value

    string | undefined

    Value is the string that will be compared to the characters of the match property.

    textValue

    string | undefined

    Sets a text value if the component's content is not plain text. This value is used in the combobox element to show the selected option.

    Returns
    ReactElement<any, string | JSXElementConstructor<any>> | null