Tag Input
The Tag Input component (<x-tag-input>) is a flexible, badge-styled input for collecting multiple values from the user — perfect for tags, labels, keywords, or recipient lists. It is built on top of Tagify and wraps it into a familiar field component that integrates seamlessly with Livewire.
Tags can be plain strings or rich objects ({ value, type }) — the latter enabling per-tag colors via the badge system. State is fully two-way bound via wire:model, including server-driven resets, suggestion whitelists and validation errors.
Basic Usage
At its simplest, the Tag Input is bound to an array property via wire:model. The user types a value and presses Enter (or a delimiter) to add it as a tag.
1<x-tag-input id="basic-tags" label="Tags" placeholder="Add a tag and press enter" />
Suggestions
Provide a list of autocomplete suggestions via the suggestions prop. As the user types, matching suggestions appear in a dropdown.
1<x-tag-input2 id="suggestions-tags"3 label="Stack"4 placeholder="Start typing..."5 :suggestions="['Laravel', 'Livewire', 'Alpine.js', 'Tailwind CSS', 'Pest', 'Inertia', 'Filament']"6/>
Enforce Whitelist
Set enforceWhitelist to true to allow only values that exist in the suggestions list. Anything else is rejected.
1<x-tag-input2 id="enforce-whitelist-tags"3 label="Allowed Tags Only"4 hint="Only tags from the whitelist can be added."5 placeholder="Pick a tag..."6 :suggestions="['Bug', 'Feature', 'Documentation', 'Question']"7 :enforceWhitelist="true"8/>
Object Mode
In object mode, each tag is stored as an object instead of a plain string. This enables per-tag colors by attaching a type (badge type) to every suggestion.
The bound property will receive an array like:
1[2 ['value' => 'Bug', 'type' => 'danger'],3 ['value' => 'Feature', 'type' => 'success'],4]
1<x-tag-input 2 id="object-mode-tags" 3 label="Issue Labels" 4 placeholder="Add a label..." 5 :objectMode="true" 6 defaultType="primary" 7 :suggestions="[ 8 ['value' => 'Bug', 'type' => 'red'], 9 ['value' => 'Feature', 'type' => 'green'],10 ['value' => 'Documentation', 'type' => 'primary'],11 ['value' => 'Question', 'type' => 'yellow'],12 ]"13/>14 15{{--16 In objectMode the wire:model property will receive an array of objects17 like [['value' => 'Bug', 'type' => 'danger'], ...] instead of plain strings.18--}}
Labels (Display vs. Value)
Decouple the displayed text from the stored value by attaching a label field to each suggestion. The user sees and searches by the human-readable label, while the underlying value (typically an ID) is what flows back into your Livewire property.
A typical suggestion looks like:
1['value' => 'user_42', 'label' => 'Anna Müller', 'type' => 'primary']
1<x-tag-input 2 id="labels-tags" 3 label="Assignees" 4 placeholder="Pick a user..." 5 :objectMode="true" 6 :enforceWhitelist="true" 7 :suggestions="[ 8 ['value' => 'user_1', 'label' => 'Anna Müller', 'type' => 'primary'], 9 ['value' => 'user_2', 'label' => 'Ben Schneider', 'type' => 'success'],10 ['value' => 'user_3', 'label' => 'Clara Fischer', 'type' => 'warning'],11 ['value' => 'user_4', 'label' => 'David Weber', 'type' => 'danger'],12 ]"13/>14 15{{--16 `label` decouples the displayed text from the stored value. Tagify will17 render and search by `label`, while `value` (e.g. a user ID) is what18 flows back into your Livewire array. Perfect for assignee pickers,19 relation selectors, or any case where the underlying identifier should20 stay hidden from the user.21--}}
Default Type
The defaultType prop sets the badge type used for tags that don't carry their own type. It maps directly to the badge color system.
| Type | Description |
|---|---|
| primary | Default — main brand color. |
| success | Positive / confirmation. |
| warning | Caution / attention. |
| danger | Errors / destructive items. |
| gray | Neutral. |
| black | High-contrast accent. |
1<x-tag-input2 id="default-type-tags"3 label="Success Tags"4 defaultType="emerald"5 placeholder="Add a tag..."6/>
Badge Style
Choose how tag badges are rendered using the badgeStyle prop. The style applies to both the rendered tags and the suggestion dropdown.
| Style | Description |
|---|---|
| solid | Default — filled background. |
| invert | Inverted color scheme. |
| label | Subtle label-like appearance. |
| outline | Bordered, transparent background. |
1<x-tag-input id="badge-style-solid" label="Solid (default)" badgeStyle="solid" 2 :suggestions="['Laravel', 'Livewire', 'Alpine.js']" /> 3 4<x-tag-input id="badge-style-invert" label="Invert" badgeStyle="invert" 5 :suggestions="['Laravel', 'Livewire', 'Alpine.js']" /> 6 7<x-tag-input id="badge-style-label" label="Label" badgeStyle="label" 8 :suggestions="['Laravel', 'Livewire', 'Alpine.js']" /> 9 10<x-tag-input id="badge-style-outline" label="Outline" badgeStyle="outline"11 :suggestions="['Laravel', 'Livewire', 'Alpine.js']" />
Max Tags
Limit the number of tags the user can add via maxTags. Once the limit is reached, further input is rejected.
1<x-tag-input2 id="max-tags-tags"3 label="Top 3 Skills"4 hint="You can add up to 3 tags."5 :maxTags="3"6 placeholder="Add a skill..."7/>
Duplicates
By default duplicate tags are rejected. Set duplicates to true to explicitly allow them.
1<x-tag-input2 id="duplicates-tags"3 label="Allow Duplicates"4 :duplicates="true"5 placeholder="Same tag twice? No problem."6/>
Pattern (Regex Validation)
Validate every tag against a regular expression using the pattern prop. Tags that don't match the pattern are visually flagged as invalid.
1<x-tag-input2 id="pattern-tags"3 label="Slugs Only"4 hint="Only lowercase letters, digits and dashes are allowed."5 pattern="^[a-z0-9-]+$"6 placeholder="my-awesome-tag"7/>
Delimiters
Customize the characters that finalize a tag. Multiple delimiters can be combined using the regex alternation syntax (|). The default is ",".
1<x-tag-input2 id="delimiters-tags"3 label="Comma or Space"4 hint="Press comma or space to finalize a tag."5 delimiters=", | "6 placeholder="laravel livewire alpine"7/>
Placeholder
Show helper text inside the empty input via the placeholder prop.
1<x-tag-input id="placeholder-tags" label="Tags" placeholder="Type something and press enter..." />
Sizes
The component supports the same sizes as other input components: sm, md, lg.
1<x-tag-input id="sizes-sm" size="sm" label="Small" placeholder="Small tag input" />2<x-tag-input id="sizes-md" size="md" label="Medium" placeholder="Medium tag input" />3<x-tag-input id="sizes-lg" size="lg" label="Large" placeholder="Large tag input" />
Disabled State
Use the disabled attribute to prevent any interaction with the component.
1<x-tag-input id="disabled-tags" label="Tags" disabled :suggestions="['Laravel', 'Livewire']" />
Read-only State
Use readonly to display existing tags without allowing edits or removals.
1<x-tag-input id="readonly-tags" label="Tags" readonly :suggestions="['Laravel', 'Livewire']" />
Subtle
Make the input blend in with the surrounding background using the subtle attribute — useful inside cards or toolbars.
1<x-tag-input id="subtle-tags" label="Subtle Tag Input" subtle placeholder="Blends with the background" />
Label Addons
Add any content next to the label using the labelAddon slot.
1<x-tag-input id="label-addon-tags" label="Tags">2 <x-slot:labelAddon> 3 <x-button size="xs" type="link" tabindex="-1">Manage tags</x-button> 4 </x-slot:labelAddon> 5</x-tag-input>
Hint Text
Use the hint attribute to display a small note between the label and the input.
1<x-tag-input id="hint-tags" label="Tags" hint="Press enter or comma to add a tag." />
Descriptions
Use the description attribute to display additional context below the input.
1<x-tag-input2 id="description-tags"3 label="Tags"4 description="Tags will be visible on the public profile."5/>
Loading State
Combine wire:loading and wire:target to show a loading indicator while Livewire is processing a request triggered by the field.
1<x-tag-input id="loading-tags" wire:model="tags" wire:loading wire:target="tags" label="Tags" placeholder="Add a tag..." />
Tagify Options (Escape Hatch)
Need a Tagify setting that isn't exposed as a prop? Pass any extra configuration through the options prop — it is merged directly into the underlying Tagify settings, overriding component defaults.
1<x-tag-input 2 id="options-tags" 3 label="Custom Tagify Settings" 4 :suggestions="['Laravel', 'Livewire', 'Alpine.js']" 5 :options="[ 6 'editTags' => true, 7 'trim' => true, 8 'dropdown' => [ 9 'enabled' => 1,10 'maxItems' => 5,11 'closeOnSelect' => true,12 ],13 ]"14/>15 16{{--17 The `options` prop is an escape hatch: anything you pass here is merged18 directly into the underlying Tagify settings, overriding component defaults.19 See https://github.com/yairEO/tagify for the full list of options.20--}}
Livewire Integration Example
A typical Livewire component using the Tag Input to collect post tags, with array validation and a reset after save:
1use Livewire\Component; 2 3class EditPost extends Component 4{ 5 /** @var array<int, string> */ 6 public array $tags = []; 7 8 public function save() 9 {10 $this->validate([11 'tags' => 'array|max:5',12 'tags.*' => 'string|max:32',13 ]);14 15 auth()->user()->posts()->create([16 'tags' => $this->tags,17 ]);18 19 $this->tags = [];20 }21 22 public function render()23 {24 return view('livewire.edit-post');25 }26}
All Attributes
Complete reference of all available attributes for the <x-tag-input> component:
| Attribute | Type | Default | Description |
|---|---|---|---|
| wire:model | String | — | Livewire property to bind tags to. Array of strings (default) or array of objects (object mode). |
| label | String | false | Label displayed above the field. |
| labelAddon | Slot / HTML | false | Extra content rendered next to the label. |
| hint | String | false | Helper text between label and input. |
| description | String | false | Description text below the input. |
| placeholder | String | false | Placeholder text inside the empty input. |
| size | String | md | Field size: sm, md, lg. |
| subtle | Boolean | false | Subtle style — blends with surroundings. |
| disabled | Boolean | false | Disables the entire field. |
| readonly | Boolean | false | Renders tags as read-only. |
| objectMode | Boolean | false | Store tags as objects ({ value, type }) instead of plain strings. |
| defaultType | String | primary | Badge type used for tags without an explicit type. |
| badgeStyle | String | solid | Badge style: solid, invert, label, outline. |
| suggestions | Array | [] | Autocomplete whitelist. Strings or { value, type, label? } objects. The optional label field is displayed to the user while value stays in the underlying state. |
| enforceWhitelist | Boolean | false | Only allow values present in suggestions. |
| maxTags | Integer | false | Maximum number of tags allowed. |
| duplicates | Boolean | false | Allow duplicate tags. |
| pattern | String (regex) | false | Regex pattern each tag must match. Invalid patterns are ignored. |
| delimiters | String | "," | Characters / regex alternation that finalize a tag. |
| options | Array | [] | Escape hatch — extra Tagify settings merged into the underlying instance. |
| show-errors | Boolean | true | Whether to render validation errors below the field. |