Skip to content

Tags Input

A neo-brutalist style tag entry component built on reka-ui primitives. Commonly used in form scenarios such as article tags, email recipients, and keyword filtering. Supports keyboard shortcuts, delimiter-based auto-add, and multiple color variants.

Demo

Preview

默认

vue
tailwind
brutalism

主要

typescript
vite
cva

次要

reka-ui
lucide
pnpm

强调

neo-brutalism
design
tokens

危险

bug
deprecated
breaking

成功

stable
tested
released

自定义 aria-label

vue
a11y

Installation

pnpm dlx brutx-vue@latest add tags-input

Usage

vue
<script setup>
import { ref } from 'vue'
import {
    TagsInput,
    TagsInputInput,
    TagsInputItem,
    TagsInputItemText,
    TagsInputItemDelete
} from 'brutx-ui-vue'

const tags = ref(['vue', 'css'])
</script>

<template>
    <TagsInput v-model="tags">
        <TagsInputItem v-for="tag in tags" :key="tag" :value="tag">
            <TagsInputItemText>{{ tag }}</TagsInputItemText>
            <TagsInputItemDelete />
        </TagsInputItem>
        <TagsInputInput placeholder="Add tag..." />
    </TagsInput>
</template>

Variants

You can customize the color scheme of individual tags using the variant prop on TagsInputItem:

VariantDescription
primaryDefault coral background with black bold border
secondaryMint green background
accentBrutal yellow background
successClassic green background
dangerClassic red background
defaultPlain white background
vue
<template>
    <TagsInputItem value="css" variant="secondary">
        <TagsInputItemText>CSS</TagsInputItemText>
        <TagsInputItemDelete />
    </TagsInputItem>
</template>

Sub-components

ComponentDescription
TagsInputRoot component that manages the tag list state
TagsInputInputText input field
TagsInputItemIndividual tag item container
TagsInputItemTextTag text content
TagsInputItemDeleteTag delete button

Props

TagsInput

PropTypeDefaultDescription
modelValueArray<T>[]Tag data list, supports v-model two-way binding
defaultValueArray<T>[]Default tag list in uncontrolled mode
disabledbooleanfalseWhether to disable input
maxnumber0Maximum number of tags allowed; 0 means no limit
addOnPastebooleanfalseWhether to auto-add tags on paste based on delimiter
addOnTabbooleanfalseWhether to add a tag when pressing the Tab key
addOnBlurbooleanfalseWhether to add a tag when the input loses focus
duplicatebooleanfalseWhether to allow adding duplicate tags
delimiterstring | RegExp','Delimiter that triggers tag addition; supports regular expressions
dir'ltr' | 'rtl'Reading direction; inherits global config when not set
convertValue(value: string) => TFunction to convert the input string to the target type; required when using objects as values
displayValue(value: T) => stringvalue.toString()Function to customize the displayed tag value
ariaLabelstringlocale default (tagsInput.label)Accessibility label; falls back to the locale default when not provided
namestringForm field name
requiredbooleanWhether the field is required

TagsInputInput

PropTypeDefaultDescription
placeholderstringInput placeholder text
autoFocusbooleanWhether to auto-focus on mount
maxLengthnumberMaximum character limit

TagsInputItem

PropTypeDefaultDescription
valueAcceptableInputValue— (required)Tag value, supports string | number | bigint | Record<string, any>
variant'default' | 'primary' | 'secondary' | 'accent' | 'danger' | 'success''primary'Visual color variant of the tag
disabledbooleanfalseWhether to disable this tag

TagsInputItemDelete

Inherits base Primitive attributes, no additional props.

TagsInputItemText

Inherits base Primitive attributes, no additional props.

Events

EventPayloadDescription
update:modelValueArray<T>Triggered when the tag list changes
addTagTTriggered when a tag is successfully added
removeTagTTriggered when a tag is successfully removed
invalidTTriggered when a tag is invalid (exceeds maximum count or is a duplicate)

Slots

TagsInput

SlotScopeDescription
default{ modelValue: Array<T> }Default slot for placing TagsInputItem and TagsInputInput

TagsInputItemDelete

SlotScopeDescription
defaultCustom delete button content; defaults to an X icon

Accessibility

  • ARIA Attributes: TagsInput provides aria-label via locale by default (e.g., "Tags Input" in English); falls back to t('tagsInput.label') when not provided
  • Custom Labels: When a more specific description is needed (e.g., "Article tags", "Recipients"), use the ariaLabel prop to customize
vue
<script setup>
import { ref } from 'vue'
import {
    TagsInput,
    TagsInputInput,
    TagsInputItem,
    TagsInputItemText,
    TagsInputItemDelete
} from 'brutx-ui-vue'

const tags = ref(['vue', 'css'])
</script>

<template>
    <TagsInput v-model="tags" aria-label="Article tags">
        <TagsInputItem v-for="tag in tags" :key="tag" :value="tag">
            <TagsInputItemText>{{ tag }}</TagsInputItemText>
            <TagsInputItemDelete />
        </TagsInputItem>
        <TagsInputInput placeholder="Add tag..." />
    </TagsInput>
</template>

FAQ

Q: How do I use objects as tag values instead of strings?

A: When tag values are objects, you must provide a convertValue function to convert the input string to the target object type. It is also recommended to provide a displayValue function to customize the tag display text. If convertValue is not provided, the component will use strings as tag values.

Q: Why doesn't adding a tag work after setting the max attribute?

A: When the number of tags reaches the max limit, new tags will not be added and the invalid event will be triggered. You can listen to this event to display a message to the user. If max is set to 0, there is no limit on the number of tags.

Q: How do I automatically split multiple tags on paste?

A: Set addOnPaste to true, and text containing delimiters will be automatically split into multiple tags when pasted. The default delimiter is a comma (,), which can be customized via the delimiter prop (supports strings and regular expressions). For example, set delimiter=";" to split by semicolons.

Brute force builds.