<script setup>
import { ref } from "vue";
import { TagInput } from "@dicehub/phi/components/tag-input";
const recipients = ref(["[email protected]"]);
</script>
<template>
<TagInput
v-model="recipients"
label="Recipients"
description="Paste comma- or newline-separated email addresses."
placeholder="[email protected]"
:validate-value="(value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)"
/>
</template>Installation
Barrel
import { TagInput } from "@dicehub/phi";Granular
import { TagInput } from "@dicehub/phi/components/tag-input";Usage
Use v-model for controlled tags and defaultValue for uncontrolled usage. Enter, comma, Tab, and blur commit the current text.
<script setup>
import { ref } from "vue";
import { TagInput } from "@dicehub/phi/components/tag-input";
const labels = ref(["frontend"]);
</script>
<template>
<TagInput v-model="labels" label="Labels" placeholder="Add a label" />
</template>The component exposes its native input as input, so a template ref can focus the field or read the underlying element.
Examples
Unrestricted Values
Uncontrolled usage seeds the tags with defaultValue and accepts any non-empty value.
<template>
<TagInput
label="Labels"
description="Accepts any non-empty value."
name="labels"
placeholder="Add a label"
required
:default-value="['frontend', 'priority']"
/>
</template>Maximum Values
maxValues stops further tags, keeps the rejected text in the input, and shows the localized limit message.
<template>
<TagInput
label="Access groups"
placeholder="Type a group name"
description="A maximum of three groups."
:max-values="3"
:default-value="['alpha']"
/>
</template>Validation
validateValue receives the candidate tag and the already accepted tags. Rejected text stays in the input with the invalid message.
<script setup>
import { ref } from "vue";
import { TagInput } from "@dicehub/phi/components/tag-input";
const environments = ref(["staging"]);
</script>
<template>
<TagInput
v-model="environments"
label="Environments"
description="Lowercase names only."
placeholder="Add an environment"
:max-values="4"
:validate-value="(value) => value === value.toLowerCase()"
/>
</template>Localization
labels replaces every string TagInput generates: the fallback input name, remove actions, and validation feedback.
<script setup>
import { TagInput } from "@dicehub/phi/components/tag-input";
const labels = {
input: "Agregar etiqueta",
removeValue: (value) => `Eliminar ${value}`,
invalidValue: (value) => `${value} no es valido.`,
maxValuesReached: (maxValues) => `Maximo de ${maxValues} etiquetas.`,
};
</script>
<template>
<TagInput label="Etiquetas" placeholder="Agregar una etiqueta" :labels="labels" :max-values="3" />
</template>Fallback Accessible Name
Without a label or aria-label, the input keeps the labels.input name, so the control stays named. Override labels.input to localize it.
<template>
<TagInput placeholder="Add a tag" :default-value="['draft']" />
<TagInput
placeholder="Agregar una etiqueta"
:labels="{ input: 'Agregar etiqueta' }"
/>
</template>Disabled
Disabled TagInput blocks typing and tag removal.
<template>
<TagInput
label="Regions"
description="Locked while the deployment is running."
disabled
:default-value="['eu-central', 'us-east']"
/>
</template>Bare TagInput (Custom Layouts)
Without label, description, or error, TagInput renders the control only. Provide aria-label or aria-labelledby.
<template>
<TagInput aria-label="Notes" placeholder="Add a note" :default-value="['checked']" />
</template>Sizes
TagInput uses the Input size scale for text, radius, and base height, and reserves extra room for tags at the smaller sizes.
<template>
<TagInput size="xs" label="Extra small" placeholder="xs" :default-value="['tag']" />
<TagInput size="sm" label="Small" placeholder="sm" :default-value="['tag']" />
<TagInput label="Base" placeholder="base (default)" :default-value="['tag']" />
<TagInput size="lg" label="Large" placeholder="lg" :default-value="['tag']" />
</template>Behavior
- Enter, comma, or Tab commits the current text as a tag. Blur commits the text too.
- Pasting comma- or newline-separated text creates every value synchronously.
- Duplicate values are ignored, so each tag appears once.
- Backspace removes the last tag only while the input is empty.
- When
maxValuesis reached orvalidateValuerejects a value, the remaining text stays in the input and the matching localized message replaces the description.
API Reference
TagInput accepts standard HTML input attributes plus the following:
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string[] | undefined | Controlled tags. Use with `v-model` or `update:modelValue`. |
defaultValue | string[] | [] | Initial tags for uncontrolled usage. |
label | string | undefined | Visible label. Enables the built-in field wrapper. |
labelTooltip | string | undefined | Tooltip text shown from the label. |
description | string | undefined | Helper text shown under the control when there is no error. |
error | string | { message: string; match?: InputErrorMatch } | undefined | Error message that marks the control invalid. |
invalid | boolean | false | Marks the control invalid. The field keeps the error slot in place of the description. |
required | boolean | undefined | Sets the required state. `false` renders the optional hint. |
disabled | boolean | false | Blocks typing and tag removal. |
size | "xs" | "sm" | "base" | "lg" | "base" | Control height and text size. |
variant | "default" | "error" | "default" | Visual variant. Errors and invalid state resolve to `error`. |
placeholder | string | undefined | Placeholder for the tag input. |
name | string | undefined | Form field name. Each accepted tag is submitted with this name. |
id | string | generated | Id for the native input that the label points at. |
autoComplete | string | "off" | Autocomplete hint for the native input. |
maxValues | number | undefined | Maximum number of tags. Further values are rejected. |
validateValue | (value: string, acceptedValues: string[]) => boolean | undefined | Rejects a candidate tag before it is added. |
labels | TagInputLabels | undefined | Overrides the generated input, remove, invalid, and limit strings. |
Slots
| Slot | Description |
|---|---|
label | Replaces the label content. |
description | Replaces the description content. |
error | Replaces the error content. |
Events
| Event | Type | Description |
|---|---|---|
update:modelValue | (value: string[]) => void | Emitted whenever tags are added or removed. |
valueChange | (value: string[]) => void | Same payload as `update:modelValue`, for non-`v-model` listeners. |
Labels
Use labels to translate every string TagInput generates.
| Key | Type | Description |
|---|---|---|
input | string | Accessible name when there is no visible label or aria-label. |
removeValue | (value: string) => string | Accessible name of a tag remove button. |
invalidValue | (value: string) => string | Feedback when validateValue rejects a value. |
maxValuesReached | (maxValues: number) => string | Feedback when maxValues is reached. |
Accessibility
Label Requirement
Prefer the label prop or label slot. Without a visible label, TagInput falls back toaria-label and then to the localized labels.input name.
Tag Removal
Every tag renders a button named by labels.removeValue, so assistive technology can remove a tag without keyboard navigation through the input.
Validation Feedback
Invalid and over-limit states set aria-invalid and associate the message througharia-describedby.