Source: https://app-studio-6167b.web.app/docs/TagInput

@app-studio/components

# TagInput

A form input component for managing a list of tags. Users can add tags by typing and pressing Enter or comma, and remove them by clicking the X button or using backspace.

[View component source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput.tsx)

## Import

```ts
import { TagInput } from '@app-studio/components';
```

New to the library? Complete [installation and provider setup](https://app-studio-6167b.web.app/docs/installation) first.

## Interactive examples

Try the component, then open Code to copy the complete example.

```jsx
import React, { useState } from 'react';
import { Vertical, Text } from 'app-studio';
import { TagInput } from '@app-studio/components';

/**
 * Default TagInput example
 */
export const DefaultTagInput = () => {
  const [tags, setTags] = useState<string[]>([]);

  return (
    <Vertical gap={20}>
      <Text>Default Tag Input:</Text>
      <TagInput
        // name="tags"
        label="Tags"
        placeholder="Type tags and press Enter..."
        tags={tags}
        onTagsChange={setTags}
        helperText="Add relevant tags for your content"
      />
      <Text fontSize={14} color="color-gray-600">
        Current tags: {Array.isArray(tags) ? tags.join(', ') : 'None'}
      </Text>
    </Vertical>
  );
};

/**
 * TagInput with custom separators
 */
export const CustomSeparatorsTagInput = () => {
  const [tags, setTags] = useState<string[]>(['react', 'typescript']);

  return (
    <Vertical gap={20}>
      <Text>Custom Separators (Enter, Comma, Space):</Text>
      <TagInput
        name="customTags"
        label="Skills"
        placeholder="Use Enter, comma, or space to add skills..."
        tags={tags}
        onTagsChange={setTags}
        separators={['enter', 'comma', 'space']}
        variant="outline"
        shape="rounded"
        size="lg"
      />
    </Vertical>
  );
};

/**
 * TagInput with maximum limit
 */
export const LimitedTagInput = () => {
  const [tags, setTags] = useState<string[]>(['javascript', 'web']);

  return (
    <Vertical gap={20}>
      <Text>Limited to 5 tags:</Text>
      <TagInput
        name="limitedTags"
        label="Technologies"
        placeholder="Add up to 5 technologies..."
        tags={tags}
        onTagsChange={setTags}
        maxTags={5}
        variant="outline"
        helperText={`${tags.length}/5 tags used`}
      />
    </Vertical>
  );
};

/**
 * TagInput with validation
 */
export const ValidatedTagInput = () => {
  const [tags, setTags] = useState<string[]>([]);

  return (
    <Vertical gap={20}>
      <Text>With Validation (3-20 chars, no duplicates):</Text>
      <TagInput
        name="validatedTags"
        label="Categories"
        placeholder="Add categories..."
        tags={tags}
        onTagsChange={setTags}
        minTagLength={3}
        maxTagLength={20}
        allowDuplicates={false}
        variant="outline"
        shape="pill"
        helperText="Tags must be 3-20 characters long"
      />
    </Vertical>
  );
};

/**
 * Disabled and ReadOnly states
 */
export const DisabledTagInput = () => {
  return (
    <Vertical gap={20}>
      <Text>Disabled State:</Text>
      <TagInput
        name="disabledTags"
        label="Disabled Tags"
        tags={['disabled', 'example']}
        isDisabled={true}
        helperText="This input is disabled"
      />

      <Text>Read-Only State:</Text>
      <TagInput
        name="readonlyTags"
        label="Read-Only Tags"
        tags={['readonly', 'example']}
        isReadOnly={true}
        isRemovable={false}
        helperText="This input is read-only"
      />
    </Vertical>
  );
};

/**
 * Custom styled TagInput
 */
export const StyledTagInput = () => {
  const [tags, setTags] = useState<string[]>(['design', 'ui']);

  return (
    <Vertical gap={20}>
      <Text>Custom Styled:</Text>
      <TagInput
        name="styledTags"
        label="Design Tags"
        placeholder="Add design-related tags..."
        tags={tags}
        onTagsChange={setTags}
        variant="none"
        shape="rounded"
        shadow={{ boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 12px' }}
        views={{
          inputContainer: {
            borderColor: 'theme-primary',
            borderWidth: '2px',
            backgroundColor: 'color-blue-50',
          },
          tag: {
            backgroundColor: 'theme-primary',
            borderColor: 'theme-primary',
          },
          tagText: {
            color: 'color-white',
          },
          tagRemove: {
            _hover: {
              backgroundColor: 'rgba(255, 255, 255, 0.2)',
            },
          },
          label: {
            color: 'theme-primary',
            fontWeight: 'bold',
          },
        }}
      />
    </Vertical>
  );
};
```

## Props

Required props are marked below. A dash indicates an unspecified default. Design system configuration can override implementation defaults.

**TagInput**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L19) |
| `name` | `string` | `—` | Field name used by forms and Formik bindings.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L21) |
| `label` | `string` | `—` | Visible label rendered alongside the input. Form-library wrappers (Switch, TextField, Checkbox, …) consume this. Not a native HTML attribute on <input>, but conventionally part of the form-control prop surface.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L23) |
| `helperText` | `string` | `—` | Helper text rendered below the input (hint / error / explanation).[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L25) |
| `error` | `string \| boolean` | `false` | Error state — usually a string for the error message, or a boolean toggle.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L27) |
| `placeholder` | `string` | `'Type and press Enter to add tags...'` | Hint displayed while the field is empty.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L29) |
| `tags` | `string[]` | `[]` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L31) |
| `defaultTags` | `string[]` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L33) |
| `onTagsChange` | `((tags: string[]) => void)` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L35) |
| `onTagAdd` | `((tag: string) => void)` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L37) |
| `onTagRemove` | `((tag: string, index: number) => void)` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L39) |
| `maxTags` | `number` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L41) |
| `minTagLength` | `number` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L43) |
| `maxTagLength` | `number` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L45) |
| `allowDuplicates` | `boolean` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L47) |
| `separators` | `TagSeparator[]` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L49) |
| `isDisabled` | `boolean` | `false` | Disables user interaction.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L51) |
| `isReadOnly` | `boolean` | `false` | Keeps the value visible without allowing edits.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L53) |
| `isAutoFocus` | `boolean` | `false` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L55) |
| `isRemovable` | `boolean` | `true` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L57) |
| `size` | `Size` `"sm"``"md"``"lg"``"xs"``"xl"` | `'md'` | Size preset for the component.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L59) |
| `shape` | `Shape` `"square"``"rounded"``"pill"``"default"` | `'default'` | Shape preset for the component.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L61) |
| `variant` | `Variant` `"outline"``"default"``"none"` | `'default'` | Visual treatment of the component.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L63) |
| `shadow` | `ViewProps \| Shadow \| Elevation` | `{}` | Shadow or elevation styling.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L65) |
| `views` | `TagInputStyles` | `{}` | Style overrides for the named internal parts.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L67) |
| `left` | View type `string \| number \| bigint \| boolean \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| React.ReactPortal \| Promise<string \| number \| bigint \| boolean \| React.ReactPortal \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| null \| undefined> \| null` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L69) |
| `right` | View type `string \| number \| bigint \| boolean \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| React.ReactPortal \| Promise<string \| number \| bigint \| boolean \| React.ReactPortal \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| null \| undefined> \| null` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L71) |
| `onFocus` | `(() => void)` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L73) |
| `onBlur` | `(() => void)` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L75) |
| `onClick` | `(() => void)` | `—` | Called when the user activates the component.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L77) |
| `menuItems` | `string[]` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L79) |
| `onMenuItemSelect` | `((item: string) => void)` | `—` | See the type and source declaration for this property.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Form/TagInput/TagInput/TagInput.props.ts#L81) |

Common inherited styling props (6)

**TagInput inherited**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `media` | `Record<string, CssProps>` | `—` | See the type and source declaration for this property. |
| `as` | `keyof JSX.IntrinsicElements` `"symbol"``"object"``"slot"``"style"``"title"``"pattern"``"form"``"animate"``"clipPath"``"filter"``"marker"``"mask"``"a"``"abbr"``"address"``"area"``"article"``"aside"``"audio"``"b"``"base"``"bdi"``"bdo"``"big"``"blockquote"``"body"``"br"``"button"``"canvas"``"caption"``"center"``"cite"``"code"``"col"``"colgroup"``"data"``"datalist"``"dd"``"del"``"details"``"dfn"``"dialog"``"div"``"dl"``"dt"``"em"``"embed"``"fieldset"``"figcaption"``"figure"``"footer"``"h1"``"h2"``"h3"``"h4"``"h5"``"h6"``"head"``"header"``"hgroup"``"hr"``"html"``"i"``"iframe"``"img"``"input"``"ins"``"kbd"``"keygen"``"label"``"legend"``"li"``"link"``"main"``"map"``"mark"``"menu"``"menuitem"``"meta"``"meter"``"nav"``"noindex"``"noscript"``"ol"``"optgroup"``"option"``"output"``"p"``"param"``"picture"``"pre"``"progress"``"q"``"rp"``"rt"``"ruby"``"s"``"samp"``"search"``"script"``"section"``"select"``"small"``"source"``"span"``"strong"``"sub"``"summary"``"sup"``"table"``"template"``"tbody"``"td"``"textarea"``"tfoot"``"th"``"thead"``"time"``"tr"``"track"``"u"``"ul"``"var"``"video"``"wbr"``"webview"``"svg"``"animateMotion"``"animateTransform"``"circle"``"defs"``"desc"``"ellipse"``"feBlend"``"feColorMatrix"``"feComponentTransfer"``"feComposite"``"feConvolveMatrix"``"feDiffuseLighting"``"feDisplacementMap"``"feDistantLight"``"feDropShadow"``"feFlood"``"feFuncA"``"feFuncB"``"feFuncG"``"feFuncR"``"feGaussianBlur"``"feImage"``"feMerge"``"feMergeNode"``"feMorphology"``"feOffset"``"fePointLight"``"feSpecularLighting"``"feSpotLight"``"feTile"``"feTurbulence"``"foreignObject"``"g"``"image"``"line"``"linearGradient"``"metadata"``"mpath"``"path"``"polygon"``"polyline"``"radialGradient"``"rect"``"set"``"stop"``"switch"``"text"``"textPath"``"tspan"``"use"``"view"` | `—` | See the type and source declaration for this property. |
| `themeMode` | `"light" \| "dark"` `"light"``"dark"` | `—` | See the type and source declaration for this property. |
| `_hover` | `string \| CssProps` | `—` | See the type and source declaration for this property. |
| `_active` | `string \| CssProps` | `—` | See the type and source declaration for this property. |
| `_focus` | `string \| CssProps` | `—` | See the type and source declaration for this property. |

For shared layout, color, and responsive properties, read [Styling & composition](https://app-studio-6167b.web.app/docs/styling) and [Responsive layouts](https://app-studio-6167b.web.app/docs/responsive). Additional native element attributes depend on the target platform.

## Usage guidance

- Give controls a visible label or an accessible name, and verify keyboard interaction. See [Accessibility](https://app-studio-6167b.web.app/docs/accessibility).
- For controlled inputs, update the value from the callback shown in the props table. Keep application state in your component or form library.
- These previews run in the browser. Check [React Native setup](https://app-studio-6167b.web.app/docs/react-native) for platform requirements and differences.
