Autocomplete

An autocomplete text field is an input that offers the user text suggestions while they type.

installyarn add @clayui/autocomplete
versionNPM Version
useimport Autocomplete from '@clayui/autocomplete';

Example

import {Provider} from '@clayui/core';
import Autocomplete from '@clayui/autocomplete';
import Form from '@clayui/form';
import React from 'react';

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

export default function App() {
	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<Form.Group>
					<label
						htmlFor="clay-autocomplete-1"
						id="clay-autocomplete-label-1"
					>
						Numbers (one-five)
					</label>
					<Autocomplete
						aria-labelledby="clay-autocomplete-label-1"
						id="clay-autocomplete-1"
						defaultItems={['one', 'two', 'three', 'four', 'five']}
						messages={{
							loading: 'Loading...',
							notFound: 'No results found',
						}}
						placeholder="Enter a number from One to Five"
					>
						{(item) => (
							<Autocomplete.Item key={item}>
								{item}
							</Autocomplete.Item>
						)}
					</Autocomplete>
				</Form.Group>
			</div>
		</Provider>
	);
}

Introduction

Autocomplete provides as a mid-level API as it was done for TreeView and follows the same standards that exist in Clay components. A new implementation of Autocomplete provides new OOTB functionality and lessens the verbose composition of the old implementation but still provides backward compatibility but will be deprecated in the next major release, so if you are using this component for the first time, consider using the new implementation.

Content

Autocomplete follows the Collection pattern, the same as TreeView and VerticalBar, it accepts static and dynamic contents. Similar to TreeView, the content accepts the Item component but the Item that belongs to Autocomplete, <Autocomplete.Item />.

Static

<Autocomplete
	messages={{
		loading: 'Loading...',
		notFound: 'No results found',
	}}
	placeholder="Enter the name of a fruit"
>
	<Autocomplete.Item key="Apples">Apples</Autocomplete.Item>
	<Autocomplete.Item key="Bananas">Bananas</Autocomplete.Item>
	<Autocomplete.Item key="Cantaloupe">Cantaloupe</Autocomplete.Item>
	<Autocomplete.Item key="Mangos">Mangos</Autocomplete.Item>
	<Autocomplete.Item key="Oranges">Oranges</Autocomplete.Item>
	<Autocomplete.Item key="Strawberries">Strawberries</Autocomplete.Item>
</Autocomplete>

Dynamic

Dynamic content works when the data comes from a service, there are two possible scenarios:

  • All data exists on the client and the filter is done on the client
  • The filter is done on the server
<Autocomplete
	messages={{
		loading: 'Loading...',
		notFound: 'No results found',
	}}
	defaultItems={[
		'Apples',
		'Bananas',
		'Cantaloupe',
		'Mangos',
		'Oranges',
		'Strawberries',
	]}
	placeholder="Enter the name of a fruit"
>
	{(item) => <Autocomplete.Item key={item}>{item}</Autocomplete.Item>}
</Autocomplete>

The most common scenario for a large list of data is the filter is done on the server and it is necessary to make a request to the server as soon as the input value changes and update the list respectively. You need to make Autocomplete a controlled component that allows you to state control.

function Example() {
	const [value, setValue] = useState('');

	const [networkStatus, setNetworkStatus] = useState(4);
	const {resource} = useResource({
		fetchPolicy: 'cache-first',
		link: 'https://api.clay.example/devs/',
		onNetworkStatusChange: setNetworkStatus,
		variables: {name: value},
	});

	return (
		<Autocomplete
			messages={{
				loading: 'Loading...',
				notFound: 'No results found',
			}}
			items={resource ?? []}
			loadingState={networkStatus}
			onChange={setValue}
			onItemsChange={() => {}}
			placeholder="Enter the name of a fruit"
			value={value}
		>
			{(item) => (
				<Autocomplete.Item key={item.name}>
					{item.name}
				</Autocomplete.Item>
			)}
		</Autocomplete>
	);
}

Internationalization

To internationalize data in Autocomplete, you must pass the data to each child of the Item. Autocomplete also handles “Not found” and “Loading” messages for the respective scenarios, it is necessary to define the internationalized messages by defining the messages prop.

Value

The value of Autocomplete by default is an empty value, but it can start with a value using the defaultValue prop. Also, a value can be controlled by providing the value and onChange properties to switch to the controlled state.

function Example() {
	const [value, setValue] = useState('Apples');

	return (
		<>
			<Autocomplete
				defaultItems={[
					'Apples',
					'Bananas',
					'Cantaloupe',
					'Mangos',
					'Oranges',
					'Strawberries',
				]}
				defaultValue="Apples"
			>
				{(item) => (
					<Autocomplete.Item key={item}>{item}</Autocomplete.Item>
				)}
			</Autocomplete>

			<Autocomplete
				defaultItems={[
					'Apples',
					'Bananas',
					'Cantaloupe',
					'Mangos',
					'Oranges',
					'Strawberries',
				]}
				onChange={setValue}
				value={value}
			>
				{(item) => (
					<Autocomplete.Item key={item}>{item}</Autocomplete.Item>
				)}
			</Autocomplete>
		</>
	);
}

Asynchronous loading

Autocomplete supports loading data asynchronously, and displays the loading indicator reflecting the current loading state, by setting the loadingState prop.

function Example() {
	const [value, setValue] = useState('');

	const [networkStatus, setNetworkStatus] = useState(4);
	const {resource} = useResource({
		fetchPolicy: 'cache-first',
		link: 'https://api.clay.example/devs/',
		onNetworkStatusChange: setNetworkStatus,
		variables: {name: value},
	});

	return (
		<Autocomplete
			messages={{
				loading: 'Loading...',
				notFound: 'No results found',
			}}
			filterKey="name"
			items={resource ?? []}
			loadingState={networkStatus}
			onChange={setValue}
			onItemsChange={() => {}}
			placeholder="Enter a name"
			value={value}
		>
			{(item) => (
				<Autocomplete.Item key={item.name}>
					{item.name}
				</Autocomplete.Item>
			)}
		</Autocomplete>
	);
}

Autocomplete also supports infinite scrolling to load more data on demand as the user scrolls. This is works with the useResource hook.

function Example() {
	const [value, setValue] = useState('');

	const [networkStatus, setNetworkStatus] = useState(4);
	const {loadMore, resource} = useResource({
		fetch: async (link, options) => {
			const result = await fetch(link, options);
			const json = await result.json();

			return {
				cursor: json.next,
				items: json.results,
			};
		},
		fetchPolicy: 'cache-first',
		link: 'https://api.clay.example/devs/',
		onNetworkStatusChange: setNetworkStatus,
		variables: {name: value},
	});

	return (
		<Autocomplete
			messages={{
				loading: 'Loading...',
				notFound: 'No results found',
			}}
			filterKey="name"
			items={resource ?? []}
			loadingState={networkStatus}
			onChange={setValue}
			onItemsChange={() => {}}
			onLoadMore={loadMore}
			placeholder="Enter a name"
			value={value}
		>
			{(item) => (
				<Autocomplete.Item key={item.name}>
					{item.name}
				</Autocomplete.Item>
			)}
		</Autocomplete>
	);
}

Custom Filtering

By default, Autocomplete uses the contains string filtering strategy to decide which items should be visible in the menu. This filtering strategy can be replaced by your own filtering rule by passing the data through the items prop.

function Example() {
	const options = [
		'Apples',
		'Bananas',
		'Cantaloupe',
		'Mangos',
		'Oranges',
		'Strawberries',
	];

	const [value, setValue] = useState('');

	const filteredItems = useMemo(
		() =>
			options.filter(
				(item) => value.match(new RegExp(value, 'i')) !== null
			),
		[value]
	);

	return (
		<Autocomplete
			messages={{
				loading: 'Loading...',
				notFound: 'No results found',
			}}
			items={filteredItems}
			onChange={setValue}
			onItemsChange={() => {}}
			placeholder="Enter the name of a fruit"
			value={value}
		>
			{(item) => <Autocomplete.Item key={item}>{item}</Autocomplete.Item>}
		</Autocomplete>
	);
}

Trigger options

By default, Autocomplete show the menu when the user types in the input field. Alternatively this mode can be modified by setting the menuTrigger property to focus, which shows the menu when Autocomplete is focused.

import {Provider} from '@clayui/core';
import Autocomplete from '@clayui/autocomplete';
import Form from '@clayui/form';
import React from 'react';

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

export default function App() {
	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4">
				<Form.Group>
					<label
						htmlFor="clay-autocomplete-2"
						id="clay-autocomplete-label-2"
					>
						Fruits
					</label>
					<Autocomplete
						aria-labelledby="clay-autocomplete-label-2"
						id="clay-autocomplete-2"
						defaultItems={[
							'Apples',
							'Bananas',
							'Cantaloupe',
							'Mangos',
							'Oranges',
							'Strawberries',
						]}
						messages={{
							loading: 'Loading...',
							notFound: 'No results found',
						}}
						placeholder="Enter the name of a fruit"
						menuTrigger="focus"
					>
						{(item) => (
							<Autocomplete.Item key={item}>
								{item}
							</Autocomplete.Item>
						)}
					</Autocomplete>
				</Form.Group>
			</div>
		</Provider>
	);
}

API Reference

ClayAutocomplete

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

component

React.ForwardRefExoticComponent<any> | undefined

Div component to render. It can be a one component that will replace the markup.

active

boolean | undefined

Flag to indicate if menu is showing or not.

as

React.ForwardRefExoticComponent<any> | "input" | ((props: React.ComponentProps<typeof Input>) => JSX.Element) | undefined

Custom input component.

alignmentByViewport

boolean | undefined

Flag to align the DropDown menu within the viewport.

allowsCustomValue

boolean | undefined

Flag to allow an input value not corresponding to an item to be set.

defaultActive

boolean | undefined

The initial value of the active state (uncontrolled).

defaultValue

string | undefined

The initial value of the input (uncontrolled).

direction

"bottom" | "top" | undefined

Direction the menu will render relative to the Autocomplete.

filterKey

string | undefined

Defines the name of the property key that is used in the items filter test (Dynamic content).

items

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

Property to render content with dynamic data.

defaultItems

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

Property to set the initial value of items (uncontrolled).

messages

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

Messages for autocomplete.

onActiveChange

any

Callback for when the active state changes (controlled).

onChange

any

Callback called when input value changes (controlled).

onItemsChange

any

Callback called when items change (controlled).

onLoadMore

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

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

value

string | undefined

The current value of the input (controlled).

menuTrigger

"input" | "focus" | undefined

The interaction required to display the menu.

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