---
title: "TagInput"
description: "An input that adds tags on Enter or a separator."
category: Form
syncStatus: reviewed
status: beta
since: 0.3.4
tags: [tag, input, form]
verified: true
---

## Usage

### Basic
::TuffDemoWrapper{demo="TagInputTagInputDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const tags = ref(['Design', 'Docs'])
  </script>

  <template>
    <TxTagInput v-model="tags" placeholder="Press Enter to add tags" />
  </template>
---
::

### Release Policy
`TxTagInput` carries searchable metadata; `max` caps the count.
::TuffDemoWrapper{demo="ComponentsReleasePolicyDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  const riskSegments = [
    { value: 1, label: 'Low' },
    { value: 2, label: 'Med' },
    { value: 3, label: 'High' },
    { value: 4, label: 'Freeze' },
  ]
  </script>

  <template>
    <TxCascader v-model="releasePath" :options="scopeOptions" placeholder="Release scope" />
    <TxFlatSelect v-model="rolloutMode" placeholder="Rollout mode">
      <TxFlatSelectItem value="phased" label="Phased" />
      <TxFlatSelectItem value="guarded" label="Guarded" />
    </TxFlatSelect>
    <TxSegmentedSlider v-model="riskLevel" :segments="riskSegments" />
    <TxSlider v-model="traffic" :min="5" :max="100" :step="5" show-value :format-value="value => value + '%'" />
    <TxTagInput v-model="labels" placeholder="Press Enter to add tags" :max="5" />
  </template>
---
::

### Best Practices

- Keep tags to short metadata; release notes, approval reasons, and other long text belong in a textarea or detail form.
- Set `max` to the smallest limit the workflow needs.
- Keep `allowDuplicates` off unless duplicate tags mean something.
- Add every delimiter your help text mentions to `separators`.
- Put labels, help text, and validation messages outside the component.

## API Reference

### Props

| Name | Type | Default | Description |
|------|------|------|------|
| `modelValue` | `string[]` | `[]` | Tag list and single source of truth; every add or remove emits a new array. |
| `placeholder` | `string` | `'Add tag'` | Placeholder text. |
| `disabled` | `boolean` | `false` | Blocks adding and removing, including the close buttons on existing tags. |
| `max` | `number` | `20` | Maximum tag count; reaching it disables the input and hides the placeholder. |
| `allowDuplicates` | `boolean` | `false` | Allows duplicates; when off, dedup is an exact, case-sensitive match after trimming. |
| `separators` | `string[]` | `[',']` | Characters that split pasted or typed text. |
| `confirmOnBlur` | `boolean` | `true` | Commits unfinished input on blur. |

### Events

| Event | Payload | Description |
|------|------|------|
| `update:modelValue` | `(tags: string[])` | Fires with the next complete list. |
| `change` | `(tags: string[])` | Fires together with `update:modelValue`. |
| `add` | `(tags: string[])` | Fires with the tags this operation actually added. |
| `remove` | `(tag: string)` | Fires with the removed tag. |
| `focus` | `(event: FocusEvent)` | Forwards the input's focus event. |
| `blur` | `(event: FocusEvent)` | Forwards the input's blur event. |

## Overview

- Input is trimmed first; empty tags are ignored.
- `separators` split pasted or typed text; Enter always confirms the current input.
- With `confirmOnBlur`, `blur` is emitted first, then the unfinished input is committed.
- Backspace removes the last tag only when the input is empty.

## Technologies

- Existing tags render with `TxTag`.
- Source: `packages/tuffex/packages/components/src/tag-input/`; exports the `TagInputProps` and `TagInputEmits` types.

<TuffDocSourceLink />
