A text field that turns what you type into removable tags when you press Enter or comma: for keywords, recipients and labels.
Press Enter or comma to add a keyword.
import { TagInput } from "@rdloom/react";
export default function TagInputBasicExample() {
return (
<div className="w-96 max-w-full">
<TagInput label="Keywords" description="Press Enter or comma to add a keyword." defaultValue={["design", "accessibility"]} placeholder="Add a keyword" />
</div>
);
}Installation
npx rdloom add tag-inputCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/tag-input.jsonWorks, but without upgrade tracking.
Usage
import { TagInput } from "@rdloom/react";
<div className="w-96 max-w-full">
<TagInput label="Keywords" description="Press Enter or comma to add a keyword." defaultValue={["design", "accessibility"]} placeholder="Add a keyword" />
</div>Limits
2 of 4. Duplicates are ignored.
import { useState } from "react";
import { TagInput } from "@rdloom/react";
export default function TagInputLimitsExample() {
const [tags, setTags] = useState<string[]>(["ada@example.com", "grace@example.com"]);
return (
<div className="w-96 max-w-full">
<TagInput
label="Recipients"
description={`${tags.length} of 4. Duplicates are ignored.`}
value={tags}
onChange={setTags}
maxTags={4}
placeholder="name@example.com"
/>
</div>
);
}Invalid
Add at least one label.
import { TagInput } from "@rdloom/react";
export default function TagInputInvalidExample() {
return (
<div className="w-96 max-w-full">
<TagInput label="Labels" isInvalid errorMessage="Add at least one label." />
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
labelrequiredVisible label, also the accessible name. | string | none |
descriptionHelp text, e.g. "Press Enter or comma to add". | string | none |
errorMessageShown when the field is invalid. | string | none |
valueControlled list of tags. | readonly string[] | none |
defaultValueInitial tags when uncontrolled. | readonly string[] | none |
onChangeCalled with the full list whenever it changes. | (tags: string[]) => void | none |
placeholderHint shown while there are no tags. | string | none |
maxTagsMost tags allowed. The input is disabled once reached. | number | none |
allowDuplicatesAllow the same tag twice. | boolean | false |
isDisabledPrevents interaction and dims the field. | boolean | false |
isInvalidMarks the field invalid. | boolean | false |
Accessibility
Role group, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Type, then Enter or comma to add a tag; pasting a comma-separated list adds each
- Backspace in an empty input removes the last tag
- Left arrow from the start of the input moves into the tags; arrows move between tags
- Delete or Backspace on a focused tag removes it, and focus moves to a neighbour
Screen readers announce
- The input is announced with the label and description, and how many tags there are
- Adding announces the tag and the new count; removing announces what was removed
- Refusing a duplicate or hitting the limit is announced with the reason
What your code must do
- The group is named by the label; tags are a list, each with a Remove button named after it
- Every add and remove is announced in a live region, e.g. "design added, 3 tags"
- Duplicates and the maximum are explained in text when refused
- The input keeps its own accessible name and description
Guidelines
Use it when
- Free-form keywords, labels and email recipients
- Lists the person builds by typing
Avoid it when
- Choosing from a fixed list: use Combobox or checkboxes
- A single value: use TextField
Don't
- No visible way to remove a tag with a mouse
- Silently dropping duplicates
- Needing a comma to submit the last tag with no Enter
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-surface-default--rd-color-surface-subtle--rd-color-border-default--rd-color-border-strong--rd-color-text-default--rd-color-text-muted--rd-color-feedback-danger--rd-color-focus-ring--rd-radius-control