Components

Tags Input

Tokenized text input with keyboard editing, paste handling, validation, and form submission.

TagsInput converts text into removable values. It supports keyboard navigation, batch paste, duplicate rules, object values, and native forms.

Use Combobox when values must come from suggestions.

Anatomy

  • #tag: Replaces an entire tag, with value, label, highlight state, and remove action.
  • #delete: Content inside each default remove button.
  • #input: Replaces the text input. Bind inputProps to preserve behavior and accessibility.
  • #clear: Content inside the optional clear-all button.

The component generates tag wrappers, remove controls, an editable input, and hidden native form controls. Style those generated parts with the matching ui keys.

Usage

Technologies

Vue
TypeScript

Press Enter or comma to add a tag. 2/5 tags.

Examples

Delimiters and blur

Enter always adds the current text. A one-character string delimiter also adds on that key. Set addOnBlur or addOnTab for data-entry workflows that need those commit points.

<template>
  <TagsInput
    v-model="keywords"
    delimiter=","
    add-on-blur
    add-on-tab
    placeholder="Add keyword"
  />
</template>

Batch paste

Set addOnPaste to split clipboard text using delimiter. Duplicate, invalid, and over-limit values emit invalid-value; accepted values commit in one model update.

<template>
  <TagsInput
    v-model="recipients"
    add-on-paste
    :delimiter="/[;,]/"
    placeholder="Paste email addresses"
  />
</template>

Validation and limits

validate receives the converted value. max makes the input read-only after the limit and reports additional values with reason max.

<script setup lang="ts">
const isEmail = (value: unknown) =>
  typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
</script>

<template>
  <TagsInput
    v-model="recipients"
    :validate="isEmail"
    :max="5"
    @invalid-value="(value, details) => showError(value, details.reason)"
  />
</template>

Number and object values

Use convertValue to produce non-string models. Pair object values with displayValue, serializeValue, and isEqual so rendering, forms, and duplicate checks use stable identities.

<template>
  <TagsInput
    v-model="users"
    name="user"
    :convert-value="name => ({ id: findId(name), name })"
    :display-value="user => user.name"
    :serialize-value="user => String(user.id)"
    :is-equal="(a, b) => a.id === b.id"
  />
</template>

Custom tag and input

Use #tag for the complete token or #delete for only the remove icon. A custom #input must bind inputProps.

<template>
  <TagsInput v-model="tags">
    <template #tag="{ label, remove, isHighlighted }">
      <span :data-active="isHighlighted || undefined">
        {{ label }}
        <button type="button" @click="remove">Remove</button>
      </span>
    </template>
    <template #input="{ inputProps }">
      <input v-bind="inputProps" aria-label="Add another tag">
    </template>
  </TagsInput>
</template>

Field integration

Inside Field, TagsInput inherits id, name, required/disabled/invalid state, and description/error IDs. A required field is invalid only after interaction or invalid submit.

<template>
  <Field label="Project labels" name="labels" required>
    <TagsInput v-model="labels" placeholder="Add label" />
  </Field>
</template>

Cancel changes

add, remove, value-change, and input-change are cancelable. Cancel the earliest relevant event to stop the operation.

<template>
  <TagsInput
    v-model="tags"
    @remove="(value, details) => value === 'required' && details.cancel()"
  />
</template>

Native Form Reset

A native form reset restores the initial model and clears interaction state. Calling preventDefault() on the reset event preserves the current value. Reset updates v-model without emitting value-change.

API Reference

Models

ModelTypeDefaultDescription
v-modelTagsInputValue[][]Accepted tag values.
v-model:inputstring""Current uncommitted text.

Props

PropTypeDefaultDescription
displayValue(value) => stringstring/JSONVisible and accessible tag label.
convertValue(text) => valueidentity stringConverts input text before validation/addition.
serializeValue(value) => stringstring/JSONSerializes native form values and keys.
isEqual(a, b) => booleanObject.isDuplicate and equality comparison.
validate(value) => booleanaccepts allValidates converted values.
delimiterstring | RegExp","Add key and paste splitting rule.
addOnBlurbooleanfalseAdds non-empty input on blur.
addOnPastebooleanfalseAdds multiple delimited clipboard values.
addOnTabbooleanfalseAdds non-empty input instead of moving focus.
duplicatebooleanfalseAllows equal values more than once.
maxnumber0Maximum count; zero means unlimited.
trimbooleantrueTrims input and pasted segments.
clearablebooleanfalseRenders a clear-all button when values exist.
placeholderstring-Editable input placeholder.
maxLengthnumber-Native character limit for uncommitted input text.
autoFocusbooleanfalseFocuses the editable input after mount.
idstringfield/generated idEditable input id.
namestringfield nameNative form field name repeated per tag.
requiredbooleanfalseRequires at least one tag.
disabledbooleanfalseDisables editing, controls, and form submission.
readOnlybooleanfalseKeeps values focusable but prevents changes.
invalidbooleanfalseForces invalid styling and ARIA state.
dir"ltr" | "rtl""ltr"Tag direction and Arrow-key behavior.
ariaLabelstring"Tags input"Accessible group/input label.
ariaLabelledbystring-Accessible label element id.
ariaDescribedbystringfield IDsAccessible description/error ids.
uiTagsInputUi-Classes for structural parts.

Emits

EventPayloadDescription
value-change(values, details)Fires before the values array updates. Cancelable.
input-change(text, details)Fires before editable text updates. Cancelable.
add(value, details)Fires before an accepted value is added. Cancelable.
remove(value, details)Fires before a value is removed. Cancelable.
invalid-value(value, details)Reports empty, convert, invalid, duplicate, or max reasons.

Slots

SlotPropsDescription
tagvalue, label, index, isHighlighted, removeComplete custom tag.
deletevalue, indexDefault remove button content.
inputvalue, inputProps, addCustom editable input. Bind inputProps.
clear-Clear-all button content.

Exposed Methods

MethodDescription
add(value?, event?)Converts and adds text through all validation/event paths.
clear(event?)Removes every tag through value-change.
focus()Focuses the editable input.

UI Options

KeyDescription
rootToken editor wrapper.
hiddenInputNative form/validity input(s).
itemEach default tag wrapper.
itemTextDefault tag text.
deleteDefault per-tag remove button.
inputEditable text input.
clearOptional clear-all button.

Styling Hooks

UI keyCSS classData attrs
rootakaza-tags-inputdata-akaza-state, data-akaza-disabled, data-akaza-readonly, data-akaza-invalid, data-akaza-focused, data-akaza-filled, data-akaza-max
hiddenInputakaza-tags-input-hidden-inputnative validity attrs
itemakaza-tags-input-itemdata-akaza-state="active", data-akaza-highlighted, data-akaza-disabled
itemTextakaza-tags-input-item-text-
deleteakaza-tags-input-deletenative disabled/ARIA label attrs
inputakaza-tags-input-inputdata-akaza-disabled, data-akaza-readonly, data-akaza-invalid
clearakaza-tags-input-clearnative disabled/ARIA label attrs

Root data-akaza-state is empty or filled. Plain class applies to the root editor. Use ui.item, ui.input, and ui.delete for internal parts.

Keyboard

KeyBehavior
Enter / delimiter keyAdd current text.
TabAdd when addOnTab; otherwise move focus normally.
input BackspaceFocus last tag when input is empty.
input boundary ArrowFocus last tag from the start edge, respecting dir.
tag ArrowLeft / ArrowRightMove between tags/input, respecting dir.
tag Home / EndFocus first/last tag.
tag Backspace / DeleteRemove focused tag and retain logical focus.
tag EscapeReturn focus to the editable input.