TAG INPUT: Multi-select chips-in-field with a listbox suggestion source
COMPOSES: .dropdown-menu | .dropdown-item (chip finish is owned — A-One link-subtle pill)
Selecting a suggestion adds a chip and removes that option from the list; Backspace in the empty field removes the last chip; each chip's × removes just that one — all three restore the option to the suggestion list. Free text never commits on its own: Enter only ever adds a highlighted/matching option (error prevention, same contract as Combobox).
Suggestion source: a static listbox of subjects. Click an option or arrow to it and press Enter to add it; its row then disappears from the list. Click a chip's × (or press Backspace in the empty field) to remove it — the option reappears.
Choose every subject the student wants to study.
<div data-controller="tag-input"><div class="tag-input"><ul class="tag-input-tags" aria-label="…"></ul><input class="tag-input-field" role="combobox" …><ul class="dropdown-menu" role="listbox">…</ul></div></div>
Default behaviour: type something that matches no option (e.g. "Latin") and press Enter — nothing is added. The field only ever commits a real, highlighted option; there is no free-text tag creation.
Preloaded: server-rendered chips (<li data-tag-input-target="tag">)
already sit in .tag-input-tags. On connect the controller reads them
and hides the matching options from the suggestion list.
Disabled: the real [disabled] attribute on
.tag-input-field greys the shell via :has(); each chip's
remove button is disabled too, so a locked selection can't be edited.
.tag-input-sm: tighter padding and gap, smaller chip and field text — for dense filter rails. The remove button stays 24×24px regardless of size (WCAG 2.5.8 has no small-size exception).
<div class="tag-input tag-input-sm">…</div>