TagPicker
Notion style tag picker with full keyboard support
Import
Installation
Source
Docs
Package
Bundle size
License
Usage
Mockdata used in all examples:
const mockdata = [{ id: 'home', name: 'Home', color: 'teal' },{ id: 'pets', name: 'Pets', color: 'blue' },{ id: 'subscriptions', name: 'Subscriptions', color: 'red' },{ id: 'personal-projects', name: 'Personal projects', color: 'lime' },{ id: 'healthcare', name: 'Healthcare', color: 'orange' },{ id: 'entertainment', name: 'Entertainment', color: 'violet' },{ id: 'rent', name: 'Rent', color: 'indigo' },{ id: 'gifts', name: 'Gifts', color: 'yellow' },];
Bare minimum example with usage as custom select:
import React, { useState } from 'react';import { TagPicker } from '@mantine/tag-picker';function Demo() {const [value, onChange] = useState(null);return (<TagPickerdata={mockdata}value={value}noValueLabel="Select category"searchPlaceholder="Search categories"description="Pick transaction category"onChange={onChange}/>);}
Create, update, delete tags
Enhance tag picker with extra logic:
enableCreate
andonTagCreate
– to allow new tags creationenableUpdate
andonTagUpdate
– to allow updates of existing tagsenableColorChange
– to allow color change (won't work withoutenableUpdate
option)enableDelete
andonTagDelete
– to allow delete existing tags
import React from 'react';import { useMantineTheme } from '@mantine/core';import { useListState, randomId } from '@mantine/hooks';import { TagPicker } from '@mantine/tag-picker';function Demo() {const theme = useMantineTheme();const [value, onChange] = useState(null);const [categoriesState, categoriesHandlers] = useListState(mockdata);const colors = Object.keys(theme.colors).filter((color) => color !== 'dark').map((color) => ({ name: color, color }));return (<TagPickerdata={categoriesState}colors={colors}value={value}description="Select or create new category"createLabel="Create category"deleteLabel="Delete category"noValueLabel="Select category"searchPlaceholder="Search categories"enableColorChangeenableCreateenableUpdateenableDeleteonChange={onChange}onTagCreate={(val) => {const category = { ...val, id: randomId() };categoriesHandlers.append(category);return category;}}onTagDelete={(id) =>categoriesHandlers.setState(categoriesState.filter((c) => c.id !== id))}onTagUpdate={(id, values) => {const category = { id, ...values };categoriesHandlers.setItem(categoriesState.findIndex((c) => c.id === id),category);}}/>);}
Change transitions
TagPicker is built with Transition component.
You can change transitions with props:
- transition – premade transition or transition object
- transitionDuration – transition duration in ms, defaults to 200ms.
- transitionTimingFunction – timing function, defaults to
theme.transitionTimingFunction
<TagPickertransition="rotate-right"transitionDuration={250}transitionTimingFunction="ease"/>
Multiple state
Multiple state is not currently supported, feel free to add this feature and add open pull request.
Keyboard support
You can perform all actions within component with keyboard only:
- When tags list is open use up and down arrows to select tag, then hit Enter to submit
- With opened tags list use Tab key to focus tag edit control, hit Space or Enter to open it
- When tag edit menu is opened hit Escape to close it or Enter to submit value
Accessibility
To provide better screen readers support use these props:
<TagPickersaveLabel="Save changes" // -> aria-label for save control inside tag edit dropdowntagNameEditLabel="Update tag name" // -> aria-label for tag name fieldeditTagLabel="Edit tag" // -> aria-label for tag edit dropdown control (horizontal dots)/>
To connect TagPicker to label use either: labelledBy
prop to set aria-labelledby
on control
or controlId
prop to connect with id:
// with id: when label is clicked tag picker control is focused<label htmlFor="my-tag-picker">My tag picker</label><TagPicker controlId="my-tag-picker" />// with labelledBy: still supports screen readers but does not focus on click<div id="my-tag-picker">My tag picker</div><TagPicker labelledBy="my-tag-picker" />