<script setup lang="ts">
import { ATagsInputInput, ATagsInputItem, ATagsInputItemDelete, ATagsInputItemText, ATagsInputRoot } from 'akar';
import { ref } from 'vue';
const modelValue = ref(['Apple', 'Banana']);
</script>
<template>
<ATagsInputRoot
v-model="modelValue"
class="text-sm color-text-highlighted px-2.5 py-1.5 rounded-md bg-background inline-flex flex-wrap gap-1.5 ring ring-ring-accented ring-inset transition-colors-280 items-center relative has-focus-visible:(ring-2 ring-primary ring-inset)"
>
<ATagsInputItem
v-for="item in modelValue"
:key="item"
:value="item"
class="text-xs color-text font-medium px-1.5 py-0.5 rounded-sm bg-background-elevated inline-flex gap-0.5 wrap-anywhere ring ring-ring-accented ring-inset items-center data-[state='active']:bg-background-accented data-[disabled]:(opacity-75 cursor-not-allowed)"
>
<ATagsInputItemText />
<ATagsInputItemDelete class="color-text-dimmed rounded-xs inline-flex transition-colors-280 items-center hover:(color-text bg-background-accented/75) disabled:pointer-events-none">
<i class="i-lucide:x shrink-0 size-3.5" />
</ATagsInputItemDelete>
</ATagsInputItem>
<ATagsInputInput
placeholder="Fruits..."
class="border-0 bg-transparent flex-1 placeholder:color-text-dimmed focus:outline-none disabled:(opacity-75 cursor-not-allowed)"
/>
</ATagsInputRoot>
</template>
Import all parts and piece them together.
<script setup>
import { ATagsInputClear, ATagsInputInput, ATagsInputItem, ATagsInputItemDelete, ATagsInputItemText, ATagsInputRoot } from 'akar';
</script>
<template>
<ATagsInputRoot>
<ATagsInputItem>
<ATagsInputItemText />
<ATagsInputItemDelete />
</ATagsInputItem>
<ATagsInputInput />
<ATagsInputClear />
</ATagsInputRoot>
</template>
One benefit of using Akar is its flexibility and low-level control over the components. However, this also means that you may need to manually construct more complex UI elements by combining multiple Akar components together.
If you feel there's a lot of elements that needs to be constructed manually using Akar, consider using Pohon UI instead. It provides a higher-level abstraction over Akar components with pre-defined styles and behaviors that can help you build UIs faster.
Contains all the tags input component parts.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
addOnBlur | booleanWhen | |
addOnPaste | booleanWhen | |
addOnTab | booleanWhen | |
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) => AcceptableInputValue)Convert the input value to the desired type. Mandatory when using objects as values and using | |
defaultValue | [] | AcceptableInputValue[]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. | |
disabled | booleanWhen | |
displayValue | value.toString() | ((value: AcceptableInputValue) => 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 | AcceptableInputValue[] | null | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
required | booleanWhen |
| Event | Type |
|---|---|
addTag | [payload: AcceptableInputValue]Event handler called when tag is added |
invalid | [payload: AcceptableInputValue]Event handler called when the value is invalid |
removeTag | [payload: AcceptableInputValue]Event handler called when tag is removed |
update:modelValue | [payload: AcceptableInputValue[]]Event handler called when the value changes |
| Slot | Type |
|---|---|
modelValue | string | Record<string, any>The controlled value of the tags input. Can be bind as |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-focused] | Present when focus on input |
[data-invalid] | Present when input value is invalid |
The component that contains the tag.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | 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 | Record<string, any>Value associated with the tags |
| Attribute | Value |
|---|---|
[data-state] | 'active' | 'inactive' |
[data-disabled] | Present when disabled |
The textual part of the tag. Important for accessibility.
| Prop | Default | Type |
|---|---|---|
as | 'span' | APrimitiveAsTag | 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. |
The button that delete the associate tag.
| Prop | Default | Type |
|---|---|---|
as | 'button' | APrimitiveAsTag | 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. |
| Attribute | Value |
|---|---|
[data-state] | 'active' | 'inactive' |
[data-disabled] | Present when disabled |
The input element for the tags input.
| Prop | Default | Type |
|---|---|---|
as | 'input' | APrimitiveAsTag | 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. |
| Attribute | Value |
|---|---|
[data-invalid] | Present when input value is invalid |
The button that remove all tags.
| Prop | Default | Type |
|---|---|---|
as | 'button' | APrimitiveAsTag | 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. |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
You can automatically add tags on paste by passing the add-on-paste prop.
<script setup lang="ts">
import { ATagsInputRoot } from 'akar';
</script>
<template>
<ATagsInputRoot
v-model="modelValue"
add-on-paste
>
…
</ATagsInputRoot>
</template>
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 { ATagsInputInput, ATagsInputItem, ATagsInputItemDelete, ATagsInputItemText, ATagsInputRoot } from 'akar';
// split by space, comma, semicolon, tab, or newline
const delimiter = /[ ,;\t\n\r]+/;
</script>
<template>
<ATagsInputRoot
v-model="modelValue"
:delimiter="delimiter"
add-on-paste
>
…
</ATagsInputRoot>
</template>
| 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. |