Skip to content

Tag Input

A text field that turns what you type into removable tags when you press Enter or comma: for keywords, recipients and labels.

Inputv0.1.0experimentalWCAG 2.2 AAView spec
design
accessibility

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-input

Copies 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.json

Works, 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

ada@example.com
grace@example.com

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.

PropTypeDefault
labelrequired

Visible label, also the accessible name.

stringnone
description

Help text, e.g. "Press Enter or comma to add".

stringnone
errorMessage

Shown when the field is invalid.

stringnone
value

Controlled list of tags.

readonly string[]none
defaultValue

Initial tags when uncontrolled.

readonly string[]none
onChange

Called with the full list whenever it changes.

(tags: string[]) => voidnone
placeholder

Hint shown while there are no tags.

stringnone
maxTags

Most tags allowed. The input is disabled once reached.

numbernone
allowDuplicates

Allow the same tag twice.

booleanfalse
isDisabled

Prevents interaction and dims the field.

booleanfalse
isInvalid

Marks the field invalid.

booleanfalse

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