TagPicker

Notion style tag picker with full keyboard support
Import
Installation
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 (
<TagPicker
data={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 and onTagCreate – to allow new tags creation
  • enableUpdate and onTagUpdate – to allow updates of existing tags
  • enableColorChange – to allow color change (won't work without enableUpdate option)
  • enableDelete and onTagDelete – 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 (
<TagPicker
data={categoriesState}
colors={colors}
value={value}
description="Select or create new category"
createLabel="Create category"
deleteLabel="Delete category"
noValueLabel="Select category"
searchPlaceholder="Search categories"
enableColorChange
enableCreate
enableUpdate
enableDelete
onChange={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
<TagPicker
transition="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:

<TagPicker
saveLabel="Save changes" // -> aria-label for save control inside tag edit dropdown
tagNameEditLabel="Update tag name" // -> aria-label for tag name field
editTagLabel="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" />