Tag fields
field :tags, as: :tags renders a polished tag/chip input — daisyUI chrome over phlex-reactive's client-only tag primitives, submitting one comma-joined param.
A tag input, written once#
as: :tags renders a tag/chip input: type-ahead over your suggestions, Enter or click to add a chip, × to remove — all client-side (form state, no server round trips). phlex-forms owns the polished chrome (label, error/hint, daisyUI styling, model binding); the behavior rides on phlex-reactive's tag primitives.
Requires phlex-reactive ≥ 0.11.4 — the :tags control is only registered when it's loaded.
f.field :tags, as: :tags, suggestions: %w[Ruby Rails Hotwire Postgres]Try it#
The widget below is the real Forms::TagField, rendered live on this page. Type to filter the suggestions, Enter or click to add a tag, × to remove one. The hidden field (inspect it) carries the comma-joined value.
Suggestions: Array or haystack Hash#
Pass an Array of tags, or a Hash of tag => haystack where the haystack is the synonym text the type-ahead filter matches against — so typing "db" surfaces "Postgres".
# plain list — the filter matches the tag text
f.field :tags, as: :tags, suggestions: %w[Ruby Rails Hotwire]
# haystack Hash — the filter matches the synonyms, the chip shows the tag
f.field :tags, as: :tags, suggestions: {
"Postgres" => "postgres database db sql",
"Redis" => "redis cache kv key value"
}The model splits the comma-joined value#
The widget submits one comma-joined param (post[tags] = "Ruby,Rails") — the primitive's wire contract. The visible type-ahead input carries no name, so it never posts a stray param; only a hidden field does. Have the model split the string back into an array:
class Post < ApplicationRecord
attribute :tags, default: [] # a text[] / JSONB column, say
# accept the widget's "Ruby,Rails" and a normal Array alike
def tags=(value)
super(value.is_a?(String) ? value.split(",").map(&:strip).reject(&:empty?) : value)
end
endA future release may ship the split writer (or an ActiveModel::Type) so field :tags, as: :tags works against attribute :tags, array: true with zero model code.
Theme parity#
Under the plain theme the widget keeps the entire client wire contract (the tag behavior still works) but ships zero daisyUI classes; the invalid state rides aria-invalid on the query input. Custom styling overrides the leaf's class seams (root_classes, chip_classes, menu_classes, …).
Constraints#
- phlex-reactive ≥ 0.11.4 is required — without it the
:tagscontrol role isn't registered (the gem still boots and every other field works). - Tags can't contain a comma — it's the value separator.
- One lifted (live-validated) tag field per form; see above.