<script setup lang="ts">
import { TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInputItemText, TagsInputRoot } from 'akar';
import { ref } from 'vue';
const modelValue = ref(['Apple', 'Banana']);
</script>
<template>
<div class="akar-demo akar-demo-TagsInput">
<TagsInputRoot
v-model="modelValue"
class="border-blackA7 p-2 border rounded-lg bg-white flex flex-wrap gap-2 w-[380px] w-full items-center"
>
<TagsInputItem
v-for="item in modelValue"
:key="item"
:value="item"
class="bg-green8 aria-[current=true]:bg-green9 color-white p-1 rounded flex gap-2 shadow-md items-center justify-center"
>
<TagsInputItemText class="text-sm pl-1" />
<TagsInputItemDelete class="hover:bg-blackA4 p-0.5 rounded bg-transparent">
<PIcon name="i-lucide-x" />
</TagsInputItemDelete>
</TagsInputItem>
<TagsInputInput
placeholder="Fruits..."
class="color-green9 placeholder:color-mauve9 text-sm px-1 rounded bg-transparent flex-1 focus:outline-none"
/>
</TagsInputRoot>
</div>
</template>@import '../_colors/black-alpha.css';
@import '../_colors/green.css';
@import '../_colors/mauve.css';
@import '../_colors/grass.css';
@scope (.akar-demo-TagsInput) {
/* reset */
button,
fieldset,
input {
all: unset;
}
}Features
- Can be controlled or uncontrolled.
- Full keyboard navigation.
- Limit the number of tags.
- Accept value from clipboard.
- Clear button to reset all tags values.
Installation
Install the component from your command line.
pnpm add akar
yarn add akar
npm install akar
bun add akar
Anatomy
Import all parts and piece them together.
<script setup>
import { TagsInputClear, TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInputItemText, TagsInputRoot } from 'akar';
</script>
<template>
<TagsInputRoot>
<TagsInputItem>
<TagsInputItemText />
<TagsInputItemDelete />
</TagsInputItem>
<TagsInputInput />
<TagsInputClear />
</TagsInputRoot>
</template>
API Reference
Root
Contains all the tags input component parts.
| Prop | Default | Type |
|---|---|---|
addOnBlur | booleanWhen | |
addOnPaste | booleanWhen | |
addOnTab | booleanWhen | |
as | "div" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
convertValue | ((value: string) => T)Convert the input value to the desired type. Mandatory when using objects as values and using | |
defaultValue | [] | T[]The value of the tags that should be added. Use when you do not need to control the state of the tags input |
delimiter | "," | string | RegExpThe character or regular expression to trigger the addition of a new tag. Also used to split tags for |
dir | "ltr" | "rtl"The reading direction of the combobox when applicable. If omitted, inherits globally from | |
disabled | booleanWhen | |
displayValue | value.toString() | ((value: T) => string)Display the value of the tag. Useful when you want to apply modifications to the value like adding a suffix or when using object as values |
duplicate | booleanWhen | |
id | string | |
max | 0 | numberMaximum number of tags. |
modelValue | T[] | nullThe controlled value of the tags input. Can be bind as | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
required | booleanWhen |
| Event | Payload |
|---|---|
addTag | payload: TEvent handler called when tag is added |
invalid | payload: TEvent handler called when the value is invalid |
removeTag | payload: TEvent handler called when tag is removed |
update:modelValue | payload: T[]Event handler called when the value changes |
| Slot (default) | Payload |
|---|---|
modelValue | string | number | bigint | Record<string, any>Current input values |
| Data attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-focused] | Present when focus on input |
[data-invalid] | Present when input value is invalid |
Item
The component that contains the tag.
| Prop | Default | Type |
|---|---|---|
as | "div" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
value* | string | number | bigint | Record<string, any>Value associated with the tags |
| Data attribute | Value |
|---|---|
[data-state] | "active" | "inactive" |
[data-disabled] | Present when disabled |
ItemText
The textual part of the tag. Important for accessibility.
| Prop | Default | Type |
|---|---|---|
as | "span" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
ItemDelete
The button that delete the associate tag.
| Prop | Default | Type |
|---|---|---|
as | "button" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Data attribute | Value |
|---|---|
[data-state] | "active" | "inactive" |
[data-disabled] | Present when disabled |
Input
The input element for the tags input.
| Prop | Default | Type |
|---|---|---|
as | "input" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
autoFocus | booleanFocus on element when mounted. | |
maxLength | numberMaximum number of character allowed. | |
placeholder | stringThe placeholder character to use for empty tags input. |
| Data attribute | Value |
|---|---|
[data-invalid] | Present when input value is invalid |
Clear
The button that remove all tags.
| Prop | Default | Type |
|---|---|---|
as | "button" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Data attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
Examples
Paste behavior
You can automatically add tags on paste by passing the add-on-paste prop.
<script setup lang="ts">
import { TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInputItemText, TagsInputRoot } from 'akar'
</script>
<template>
<TagsInputRoot
v-model="modelValue"
add-on-paste
>
…
</TagsInputRoot>
</template>
Multiple delimiters
You can pass RegExp as delimiter to allow multiple characters to trigger addition of a new tag. When add-on-paste is passed it will be also used to split tags for @paste event.
<script setup lang="ts">
import { TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInputItemText, TagsInputRoot } from 'akar'
// split by space, comma, semicolon, tab, or newline
const delimiter = /[ ,;\t\n\r]+/
</script>
<template>
<TagsInputRoot
v-model="modelValue"
:delimiter="delimiter"
add-on-paste
>
…
</TagsInputRoot>
</template>
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Delete | When tag is active, remove it and set the tag on right active. |
| Backspace | When tag is active, remove it and set the tag on left active. If there are no tags to the left, either the next tags gets focus, or the input. |
| ArrowRight | Set the next tag active. |
| ArrowLeft | Set the previous tag active. |
| Home | Set the first tag active |
| End | Set the last tag active |