React Tag Input
React Tag Input is a comprehensive and user-friendly tagging component designed for React applications, currently stable at version 6.10.6. It offers robust features such as autocomplete based on a suggestion list, full keyboard and mouse navigation, drag-and-drop tag reordering powered by `react-dnd`, and in-place tag editing. The library is actively maintained with frequent patch and minor releases, and version 7 is currently in preparation. A key differentiator is its focus on accessibility and a user experience inspired by email 'To' fields, providing a flexible solution for managing tag inputs in various UI contexts.
Common errors
-
Module not found: Can't resolve 'react-tag-input'
cause The `react-tag-input` package or one of its peer dependencies is not installed or incorrectly referenced in your project.fixRun `npm install --save react-tag-input react react-dom react-dnd react-dnd-html5-backend` or `yarn add react-tag-input react react-dom react-dnd react-dnd-html5-backend`. -
TypeError: Cannot read properties of undefined (reading 'Provider')
cause This error typically indicates that `react-dnd` or its `html5-backend` peer dependency is missing or not correctly set up, which `react-tag-input` requires for drag-and-drop functionality.fixVerify that `react-dnd` and `react-dnd-html5-backend` are installed with compatible versions (`^14.0.2 || ^16.0.0` for `react-dnd`, `^14.0.0 || ^16.0.0` for `react-dnd-html5-backend`). Ensure your component tree is wrapped with `DndProvider` if you are using a custom setup, though `react-tag-input` often handles this internally via `WithContext`. -
Property 'autofocus' does not exist on type 'IntrinsicAttributes & ...'
cause You are using the deprecated `autofocus` prop (lowercase 'f') with TypeScript, which now expects `autoFocus` (camelCase 'F'). This was changed in v6.10.0.fixUpdate your code to use `autoFocus={true}` instead of `autofocus={true}`. -
Tag is not being added when `allowUnique` is true, but it looks new.
cause The `allowUnique` prop prevents tags with existing IDs from being added. Before v6.7.1, it would not properly hide suggestions for existing tags, leading to confusion.fixEnsure your tags have truly unique `id` properties. If you're on an older version and experiencing UI inconsistencies with `allowUnique`, upgrade to `react-tag-input@6.7.1` or newer to benefit from improved suggestion filtering.
Warnings
- breaking Version 7 (v7.xx) is currently in preparation and is expected to introduce breaking changes. Refer to the migration guide when upgrading.
- deprecated The `autofocus` prop was deprecated in v6.10.0 in favor of `autoFocus` (camelCase). Using `autofocus` will result in warnings and may be removed in future versions.
- gotcha The package has mandatory peer dependencies on `react`, `react-dom`, `react-dnd`, and `react-dnd-html5-backend`. Failing to install these (or installing incompatible versions) will prevent the component from functioning correctly, especially drag-and-drop.
- gotcha Prior to version 6.10.4, Korean input could trigger the `keydown` event twice, leading to incorrect or duplicate tag input behavior.
- gotcha In earlier v6 versions (before 6.10.3/6.10.4), there were issues with the `className` and `classNames` props not being correctly typed or passed to the DOM, potentially affecting styling and accessibility.
Install
-
npm install react-tag-input -
yarn add react-tag-input -
pnpm add react-tag-input
Imports
- ReactTags (aliased)
import ReactTags from 'react-tag-input';
import { WithContext as ReactTags } from 'react-tag-input'; - SEPARATORS
const SEPARATORS = require('react-tag-input').SEPARATORS;import { SEPARATORS } from 'react-tag-input'; - Tag (type)
import { Tag } from 'react-tag-input';import type { Tag } from 'react-tag-input';
Quickstart
import React from 'react';
import { createRoot } from 'react-dom/client';
import { WithContext as ReactTags, SEPARATORS } from 'react-tag-input';
import type { Tag } from 'react-tag-input'; // Assuming type Tag is exported directly
const COUNTRIES = [
'Afghanistan', 'Albania', 'Algeria', 'Andorra', 'Angola', 'Antigua and Barbuda',
'Argentina', 'Armenia', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain',
'Bangladesh', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bhutan',
];
const suggestions = COUNTRIES.map((country) => ({
id: country,
text: country,
className: '',
}));
const KeyCodes = {
comma: 188,
enter: [10, 13],
};
const App = () => {
const [tags, setTags] = React.useState<Array<Tag>>([
{ id: 'Thailand', text: 'Thailand', className: '' },
{ id: 'India', text: 'India', className: '' },
{ id: 'Vietnam', text: 'Vietnam', className: '' },
{ id: 'Turkey', text: 'Turkey', className: '' },
]);
const handleDelete = (index: number) => {
setTags(tags.filter((_, i) => i !== index));
};
const onTagUpdate = (index: number, newTag: Tag) => {
const updatedTags = [...tags];
updatedTags.splice(index, 1, newTag);
setTags(updatedTags);
};
const handleAddition = (tag: Tag) => {
setTags((prevTags) => [...prevTags, tag]);
};
const handleDrag = (tag: Tag, currPos: number, newPos: number) => {
const newTags = tags.slice();
newTags.splice(currPos, 1);
newTags.splice(newPos, 0, tag);
setTags(newTags);
};
const handleTagClick = (index: number) => {
console.log('The tag at index ' + index + ' was clicked');
};
const onClearAll = () => {
setTags([]);
};
return (
<div className="app">
<h1>React Tags Example</h1>
<p>Start typing to see suggestions. Use Enter or Comma to add tags. Click to edit, drag to reorder.</p>
<ReactTags
tags={tags}
suggestions={suggestions}
handleDelete={handleDelete}
handleAddition={handleAddition}
handleDrag={handleDrag}
handleTagClick={handleTagClick}
onTagUpdate={onTagUpdate}
onClearAll={onClearAll}
delimiters={KeyCodes.enter.concat(KeyCodes.comma)}
placeholder="Add new tags..."
inputFieldPosition="bottom"
autocomplete
allowUnique
/>
<div style={{ marginTop: '20px' }}>
<h3>Current Tags:</h3>
<ul>
{tags.map(tag => (
<li key={tag.id}>{tag.text}</li>
))}
</ul>
</div>
</div>
);
};
const container = document.getElementById('root');
if (container) {
const root = createRoot(container);
root.render(<App />);
} else {
console.error('Root element not found');
}