Tag Input

A chip-based multi-value text field — tags for segments, recipients, categories, and the like. Type and press Enter (or comma) to add; Backspace on an empty field removes the last tag.

Colors

primary
secondary
accent
neutral
info
success

Real use · post tags (max 6, dedupe on)

designuitokens

3 / 6 tags — design, ui, tokens

Using Tag Input

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Tag Input is styled but inert: its behavior comes from tag-input. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class tag-input, with 17 modifiers:

  • .tag-input
  • .tag-input-accent
  • .tag-input-chip
  • .tag-input-chip-label
  • .tag-input-error
  • .tag-input-field
  • .tag-input-info
  • .tag-input-lg
  • .tag-input-md
  • .tag-input-neutral
  • .tag-input-primary
  • .tag-input-remove
  • .tag-input-secondary
  • .tag-input-sm
  • .tag-input-success
  • .tag-input-warning
  • .tag-input-xl
  • .tag-input-xs

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { TagInput } from "@wizeworks/silicaui-react";

Props

PropTypeRequiredDescription
valuestring[]noControlled tag list.
defaultValuestring[]noUncontrolled initial tags.
onValueChange(tags: string[]) => voidnoCalled with the next tag list whenever it changes.
placeholderstringnoPlaceholder shown in the text field when there are no tags.
disabledbooleannoDisable the whole control.
colorSilicaColornoChip + focus-ring accent color.
sizeTagInputSizenoHeight/type scale. Default "md".
separatorsstring[]noKeys that commit the current text as a tag. Default ["Enter", ","].
dedupebooleannoReject duplicate tags. Default true.
maxnumbernoMaximum number of tags.
addOnBlurbooleannoCommit any pending text when the field loses focus. Default true.
inputPropsReact.InputHTMLAttributes<HTMLInputElement>noExtra props for the inner <input>.

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { useState } from "react";
import { TagInput } from "@wizeworks/silicaui-react";
import { Section, Stack } from "../lib/Section";
import { COLORS } from "../lib/data";

export function TagInputDemo() {
    const [tags, setTags] = useState<string[]>(["design", "ui", "tokens"]);

    return (
        <>
            <Section title="Colors">
                <Stack className="max-w-md">
                    {COLORS.slice(0, 6).map((color) => (
                        <TagInput
                            key={color}
                            color={color}
                            defaultValue={[color]}
                            placeholder="Add a tag…"
                        />
                    ))}
                </Stack>
            </Section>

            <Section title="Real use · post tags (max 6, dedupe on)">
                <div className="flex max-w-md flex-col gap-2">
                    <TagInput
                        color="primary"
                        value={tags}
                        onValueChange={setTags}
                        placeholder="Press Enter or , to add"
                        max={6}
                    />
                    <p className="text-xs opacity-60">
                        {tags.length} / 6 tags — {tags.join(", ") || "none yet"}
                    </p>
                </div>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

TagInput — chips + a text field. The template part is what lets the handler create new chips without hardcoding class names in the runtime, which would break under a SilicaProvider prefix. Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("TagInput", "tag-input", { /* props */ });
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "tag-input tag-input-primary" rather than passing a colour as a prop.

Takes children
no
Hydrated by
tag-input

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Tag Input, on every path, is available through the Silica MCP server.