Tags Input
Multi-value field that surfaces selections as removable inline tags, with toggle, typeable, and creatable modes.
Basic
Typeable
Set typeable to make the field itself an input. Tags render before the caret; typing filters the listbox; ArrowLeft from an empty input focuses the last tag.
Toggle with search
Pair the default toggle mode with searchable to render a sticky search input inside the listbox while keeping tags inside the toggle.
Sizes
Label, description, and help text
Combine label, sublabel, description, and help_text for the full form-field chrome.
Used to surface this post in topic feeds.
Pre-selected values
Pass a list to value to seed the initial selection. Each matching option renders as a tag on first paint.
Option formats
Options accept any shape Phoenix.HTML.Form.options_for_select/2 understands: bare strings, keyword pairs, ranges, and more.
Disabled options
Mark individual options with disabled: true. They are visually muted, ignored on click, and skipped during keyboard navigation.
Grouped and nested options
Wrap options in {group_label, children} tuples. Groups can nest to any depth and each level receives a --depth CSS variable for indentation.
Clearable
Pass clearable to render a clear button that removes every selected tag at once. Hidden whenever min > 0.
Inner affixes
:inner_prefix sits inside the field on the left; :inner_suffix replaces the default chevron, so render your own indicator if one is still needed.
Outer affixes (input group)
:outer_prefix and :outer_suffix sit beside the field, sharing a border to form a single input group.
Header and footer slots
:header and :footer stay pinned in the listbox while options scroll. Drop suggestion chips above the list, or a 'create new' action below it.
Validation errors
Pass errors as a list of strings to render messages and apply invalid styling. Bound forms populate this automatically once the input has been touched.
Pick at least one category
Disabled
Form integration
Bind to a Phoenix form field with field={f[:tags]}. Name, value, id, and errors are derived from the form, and a hidden multi-select keeps standard form submissions working. Every selection change round-trips through phx-change.
Selection limits with live count
Combine min and max with a server-rendered help_text count. The component disables remove buttons at the floor and silently rejects further selections at the ceiling; a real changeset enforces the same bounds on submit.
Creatable with server normalization
Pair typeable with creatable so pressing Enter on a non-matching value commits a new tag. The server slugifies the typed text, dedupes case-insensitively, and patches the option list back so the chip persists with a clean canonical value.
Server-driven search
Pass on_search with a LiveView event name. The component debounces typing, shows a loading indicator, and patches the option list in place. The handler must always include currently-selected options in its response or the chips disappear on the next patch.
Cascading dependent fields
One field's value drives another's options. Selecting a department populates the team list from the server; switching department drops any previously-selected teams that no longer apply, and the listbox patches in place.
Server-pushed selection
The server can swap the selection at any time by re-rendering the form with a new value. The component reconciles tags against the hidden <select> on every patch, so external triggers (preset buttons, suggestions, undo) update the chips without a remount.
Assignee picker (option and tag slots)
Combine :option for rich listbox rows, :tag for compact chips in the field, and on_search for a debounced server query. Always preserve currently-selected users in search responses so chips don't disappear mid-typing.