A TextInputWithTokens
component supports all of the features of a TextInput component, but it can render a list of Tokens next to the area a user types in.
const BasicExample = () => {const [tokens, setTokens] = React.useState([{text: 'zero', id: 0},{text: 'one', id: 1},{text: 'two', id: 2}])const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<FormControl><FormControl.Label>Basic example tokens</FormControl.Label><TextInputWithTokens tokens={tokens} onTokenRemove={onTokenRemove} /></FormControl>)}render(BasicExample)
By default, the Token
component is used to render the tokens in the input. If this component does not make sense for the kinds of tokens you're rendering, you can pass a component to the tokenComponent
prop
const UsingIssueLabelTokens = () => {const [tokens, setTokens] = React.useState([{text: 'enhancement', id: 1, fillColor: '#a2eeef'},{text: 'bug', id: 2, fillColor: '#d73a4a'},{text: 'good first issue', id: 3, fillColor: '#0cf478'}])const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<FormControl><FormControl.Label>Issue labels</FormControl.Label><TextInputWithTokens tokenComponent={IssueLabelToken} tokens={tokens} onTokenRemove={onTokenRemove} /></FormControl>)}render(<UsingIssueLabelTokens />)
By default, all tokens will be visible when the component is rendered.
If the component is being used in an area where it's height needs to be constrained, there are options to limit the height of the input.
const VisibleTokenCountExample = () => {const [tokens, setTokens] = React.useState([{text: 'zero', id: 0},{text: 'one', id: 1},{text: 'two', id: 2},{text: 'three', id: 3}])const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<Box maxWidth="500px"><FormControl><FormControl.Label>Tokens truncated after 2</FormControl.Label><TextInputWithTokens visibleTokenCount={2} block tokens={tokens} onTokenRemove={onTokenRemove} /></FormControl></Box>)}render(VisibleTokenCountExample)
const PreventTokenWrappingExample = () => {const [tokens, setTokens] = React.useState([{text: 'zero', id: 0},{text: 'one', id: 1},{text: 'two', id: 2},{text: 'three', id: 3},{text: 'four', id: 4},{text: 'five', id: 5},{text: 'six', id: 6},{text: 'seven', id: 7}])const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<Box maxWidth="500px"><FormControl><FormControl.Label>Tokens on one line</FormControl.Label><TextInputWithTokenspreventTokenWrappingblocktokens={tokens}onTokenRemove={onTokenRemove}id="inputWithTokens-basic"/></FormControl></Box>)}render(PreventTokenWrappingExample)
const MaxHeightExample = () => {const [tokens, setTokens] = React.useState([{text: 'zero', id: 0},{text: 'one', id: 1},{text: 'two', id: 2},{text: 'three', id: 3},{text: 'four', id: 4},{text: 'five', id: 5},{text: 'six', id: 6},{text: 'seven', id: 7}])const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<Box maxWidth="500px"><FormControl><FormControl.Label>Tokens restricted to a max height</FormControl.Label><TextInputWithTokensmaxHeight="50px"blocktokens={tokens}onTokenRemove={onTokenRemove}id="inputWithTokens-basic"/></FormControl></Box>)}render(MaxHeightExample)
const ErrorExample = () => {const [tokens, setTokens] = React.useState([{text: 'zero', id: 0},{text: 'one', id: 1},{text: 'two', id: 2}])const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<><Box as="label" display="block" htmlFor="inputWithTokens-basic">Basic example tokens</Box><TextInputWithTokenstokens={tokens}onTokenRemove={onTokenRemove}id="inputWithTokens-basic"validationStatus="error"/></>)}render(ErrorExample)
const LeadingVisualExample = () => {const [dates, setDates] = React.useState([{text: '01 Jan', id: 0},{text: '01 Feb', id: 1},{text: '01 Mar', id: 2}])const [tokens, setTokens] = React.useState([{text: 'zero', id: 0},{text: 'one', id: 1},{text: 'two', id: 2}])const onDateRemove = tokenId => {setDates(dates.filter(token => token.id !== tokenId))}const onTokenRemove = tokenId => {setTokens(tokens.filter(token => token.id !== tokenId))}return (<><FormControl><FormControl.Label>Dates</FormControl.Label><TextInputWithTokens leadingVisual={CalendarIcon} tokens={dates} onTokenRemove={onDateRemove} /></FormControl><FormControl><FormControl.Label>Tokens</FormControl.Label><TextInputWithTokens trailingVisual={CheckIcon} tokens={tokens} onTokenRemove={onTokenRemove} /></FormControl></>)}render(LeadingVisualExample)
const WithIconAndLoadingIndicator = () => {const [dates, setDates] = React.useState([{text: '01 Jan', id: 0},{text: '01 Feb', id: 1},{text: '01 Mar', id: 2}])const onDateRemove = tokenId => {setDates(dates.filter(token => token.id !== tokenId))}const [loading, setLoading] = React.useState(true)const toggleLoadingState = () => {setLoading(!loading)}return (<><Box mb={5} display="flex" justifyContent="flex-end"><button type="button" onClick={toggleLoadingState}>Toggle loading state {loading ? 'off' : 'on'}</button></Box><h3>No visual</h3><Box mb={2}><TextInputWithTokens tokens={dates} onTokenRemove={onDateRemove} value="auto" loading={loading} /></Box><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}value="leading"loading={loading}loaderPosition="leading"/></Box><Box mb={5}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}value="trailing"loading={loading}loaderPosition="trailing"/></Box><h3>Leading visual</h3><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}leadingVisual={CalendarIcon}loading={loading}value="auto"/></Box><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}leadingVisual={CalendarIcon}loading={loading}loaderPosition="leading"value="leading"/></Box><Box mb={5}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}leadingVisual={CalendarIcon}loading={loading}loaderPosition="trailing"value="trailing"/></Box><h3>Trailing visual</h3><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}trailingVisual={CalendarIcon}loading={loading}value="auto"/></Box><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}trailingVisual={CalendarIcon}loading={loading}loaderPosition="leading"value="leading"/></Box><Box mb={5}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}trailingVisual={CalendarIcon}loading={loading}loaderPosition="trailing"value="trailing"/></Box><h3>Both visuals</h3><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}size="small"leadingVisual={CalendarIcon}trailingVisual={CalendarIcon}loading={loading}value="auto"/></Box><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}leadingVisual={CalendarIcon}trailingVisual={CalendarIcon}loading={loading}loaderPosition="leading"value="leading"/></Box><Box mb={2}><TextInputWithTokenstokens={dates}onTokenRemove={onDateRemove}size="large"leadingVisual={CalendarIcon}trailingVisual={CalendarIcon}loading={loading}loaderPosition="trailing"value="trailing"/></Box></>)}render(<WithIconAndLoadingIndicator />)
Name | Type | Default | Description |
---|---|---|---|
tokens Required | TokenProps[] | The array of tokens to render | |
onTokenRemove Required | (tokenId: string|number) => void | The function that gets called when a token is removed | |
tokenComponent | React.ComponentType<any> | Token | The component used to render each token |
maxHeight | React.CSSProperties['maxHeight'] | The maximum height of the component. If the content in the input exceeds this height, it will scroll vertically | |
preventTokenWrapping | boolean | false | Whether tokens should render inline horizontally. By default, tokens wrap to new lines |
size | 'small' | 'medium' | 'large' | 'xlarge' | xlarge | The size of the tokens and text input |
hideTokenRemoveButtons | boolean | false | Whether the remove buttons should be rendered in the tokens |
validationStatus | 'error' | 'success' | 'warning' | Style the input to match the status | |
visibleTokenCount | number | The number of tokens to display before truncating | |
Additional props are passed to the <TextInput> element. See TextInput docs for a list of props accepted by the <TextInput> element. If an as prop is specified, the accepted props will change accordingly. |
The array passed to the tokens
prop needs to be manually updated to add and remove tokens.
The function passed to the onRemoveToken
prop is called when:
Backspace
key when the input is emptyBackspace
keyThere is no function that gets called to "add" a token, so the user needs to be provided with a UI to select tokens.