Autocomplete
Autocomplete allows users to quickly filter through a list of options and pick one or more values for a field.
Page navigation navigation
React examples
Default
<FormControl> <FormControl.Label id="autocompleteLabel-default">Label</FormControl.Label> <Autocomplete> <Autocomplete.Input /> <Autocomplete.Overlay> <Autocomplete.Menu selectedItemIds={[]} aria-labelledby="autocompleteLabel-default" items={[ {text: 'Components', id: '0'}, {text: 'Figma', id: '1'}, {text: 'Design patterns', id: '2'}, {text: 'Design tokens', id: '3'}, {text: 'Icons', id: '4'}, {text: 'Rails', id: '5'}, {text: 'React', id: '6'}, ]} /> </Autocomplete.Overlay> </Autocomplete> </FormControl>
Multi-select
import React from 'react' import {Autocomplete, FormControl} from '@primer/react' export default function Multiselect() { const [selectedItemIds, setSelectedItemIds] = React.useState<Array<string>>([]) return ( <> <FormControl> <FormControl.Label id="autocompleteLabel-multiselect">Label</FormControl.Label> <Autocomplete> <Autocomplete.Input /> <Autocomplete.Overlay> <Autocomplete.Menu selectionVariant="multiple" selectedItemIds={selectedItemIds} onSelectedChange={newlySelectedItems => { // TODO: remove this check when/if we fix the `onSelectedChange` type in PRC if (!Array.isArray(newlySelectedItems)) { return } setSelectedItemIds(newlySelectedItems.map(item => item.id)) }} aria-labelledby="autocompleteLabel-multiselect" items={items} /> </Autocomplete.Overlay> </Autocomplete> </FormControl> {selectedItemIds.length > 0 && ( <div style={{marginTop: '1rem'}}> Selected items: <ul style={{marginTop: 0}}> {items .filter(item => selectedItemIds.includes(item.id)) .map(item => ( <li key={item.id}>{item.text}</li> ))} </ul> </div> )} </> ) } const items = [ {text: 'Components', id: '0'}, {text: 'Figma', id: '1'}, {text: 'Design patterns', id: '2'}, {text: 'Design tokens', id: '3'}, {text: 'Icons', id: '4'}, {text: 'Rails', id: '5'}, {text: 'React', id: '6'}, ]
Multi-select with tokens for selected items
import React from 'react' import {Autocomplete, FormControl, TextInputWithTokens} from '@primer/react' export default function MultiselectTokens() { const [tokens, setTokens] = React.useState<Array<{text: string; id: string}>>([]) const selectedTokenIds = tokens.map(token => token.id) const [selectedItemIds, setSelectedItemIds] = React.useState<string[]>(selectedTokenIds) const onTokenRemove: (tokenId: string | number) => void = tokenId => { setTokens(tokens.filter(token => token.id !== tokenId)) setSelectedItemIds(selectedItemIds.filter(id => id !== tokenId)) } return ( <FormControl> <FormControl.Label id="autocompleteLabel-multiselect-tokens">Label</FormControl.Label> <Autocomplete> <Autocomplete.Input as={TextInputWithTokens} tokens={tokens} onTokenRemove={onTokenRemove} /> <Autocomplete.Overlay> <Autocomplete.Menu selectionVariant="multiple" selectedItemIds={selectedItemIds} onSelectedChange={newlySelectedItems => { if (!Array.isArray(newlySelectedItems)) { return } setSelectedItemIds(newlySelectedItems.map(item => item.id)) if (newlySelectedItems.length < selectedItemIds.length) { const newlySelectedItemIds = newlySelectedItems.map(({id}) => id) const removedItemIds = selectedTokenIds.filter(id => !newlySelectedItemIds.includes(id)) for (const removedItemId of removedItemIds) { onTokenRemove(removedItemId) } return } setTokens(newlySelectedItems.map(({id, text}) => ({id, text}))) }} aria-labelledby="autocompleteLabel-multiselect-tokens" items={items} /> </Autocomplete.Overlay> </Autocomplete> </FormControl> ) } const items = [ {text: 'Components', id: '0'}, {text: 'Figma', id: '1'}, {text: 'Design patterns', id: '2'}, {text: 'Design tokens', id: '3'}, {text: 'Icons', id: '4'}, {text: 'Rails', id: '5'}, {text: 'React', id: '6'}, ]
Adding new items from input
When the user isn't limited to a pre-defined list, an additional menu item can be added to select the value they typed.
import {Autocomplete, FormControl} from '@primer/react' import React from 'react' export default function Default() { const [inputValue, setInputValue] = React.useState<string>('') return ( <FormControl> <FormControl.Label id="autocompleteLabel-add-new">Label</FormControl.Label> <Autocomplete> <Autocomplete.Input value={inputValue} onChange={e => { setInputValue(e.currentTarget.value) }} /> <Autocomplete.Overlay> <Autocomplete.Menu selectedItemIds={[]} aria-labelledby="autocompleteLabel-add-new" addNewItem={ inputValue && !items.map(item => item.text).includes(inputValue) ? { text: inputValue, id: inputValue, // `handleAddItem` callback isn't needed for this specific example, // but it's included here to show that it exists handleAddItem: selectedItem => { // eslint-disable-next-line no-console console.log('added item:', selectedItem) return }, } : undefined } items={items} /> </Autocomplete.Overlay> </Autocomplete> </FormControl> ) } const items = [ {text: 'Components', id: '0'}, {text: 'Figma', id: '1'}, {text: 'Design patterns', id: '2'}, {text: 'Design tokens', id: '3'}, {text: 'Icons', id: '4'}, {text: 'Rails', id: '5'}, {text: 'React', id: '6'}, ]
Loading
A loading indicator should be displayed while the data for the list of options is being populated. The loading indicator helps the user understand that the list is not empty, it's just not done loading.
import {Autocomplete, FormControl} from '@primer/react' import React from 'react' export default function Loading() { return ( <FormControl> <FormControl.Label id="autocompleteLabel-loading">Label</FormControl.Label> <Autocomplete> <Autocomplete.Input /> <Autocomplete.Overlay> <Autocomplete.Menu loading selectedItemIds={[]} aria-labelledby="autocompleteLabel-loading" items={[]} /> </Autocomplete.Overlay> </Autocomplete> </FormControl> ) }
More code examples
See the Autocomplete Storybook stories.
Props
Loading data for autocomplete...