タグ入力
stimeo--tags-input
自由入力チップ。Enter / 区切り文字でタグを追加・削除する。
stimeo--tags-input コントローラは、テキスト入力をタグ(チップ)入力欄にする。 Enter または設定した区切り文字で、トリム済みの入力値をタグとして確定する。空・重複(allowDuplicates 時を除く)・上限(max)超過の追加は stimeo--tags-input:reject で拒否する。タグはテンプレートから生成し、各タグに Remove {label} のボタンを付与する。 fields コンテナはタグ集合を name 付き hidden input として同期し、フォーム送信に使える。削除ボタンは 1 つのロービング Tab ストップで、←/→ で移動し(右端の先は入力欄へ戻る)、Delete/Backspace でフォーカス中のタグを削除、空入力の Backspace で末尾タグを削除する。削除後はフォーカスを隣のタグ、無ければ入力欄へ移す。変化のたびに stimeo--tags-input:change を発火する。
キーボード操作
| キー | 動作 |
|---|---|
| Enter / 区切り文字 | 入力中の文字列をタグとして確定。 |
| Backspace(空入力) | 直前のタグを削除。 |
| ← / → | タグ削除ボタン間を移動(右端の先は入力欄へ戻る)。 |
| Delete / Backspace(タグ上) | フォーカス中のタグを削除。 |
<%# Markup for the tags-input demo.
Enter or a comma (delimiter) turns the input value into a tag, blocking duplicates /
empties / over-limit. Tag remove buttons move via roving (left/right keys), and
Backspace on an empty input deletes the previous tag. The library handles tag
create/remove, hidden-field sync, focus handoff, and live announcements. %>
<div class="tags-input" data-controller="stimeo--tags-input"
data-stimeo--tags-input-delimiter-value=","
data-stimeo--tags-input-name-value="frameworks[]">
<ul
class="tags-input__tags"
role="list"
aria-label="<%= t("components.tags_input.demo.tags_label") %>"
data-stimeo--tags-input-target="tags"></ul>
<input
type="text"
class="tags-input__input"
aria-label="<%= t("components.tags_input.demo.input_label") %>"
aria-describedby="tags-input-help"
data-stimeo--tags-input-target="input"
data-action="keydown->stimeo--tags-input#onKeydown" />
<span id="tags-input-help" class="tags-input__help">
<%= t("components.tags_input.demo.help") %>
</span>
<span
role="status"
aria-live="polite"
class="tags-input__status visually-hidden"
data-stimeo--tags-input-target="status"></span>
<%# The library creates and syncs the submit hidden inputs as name="frameworks[]". %>
<div hidden data-stimeo--tags-input-target="fields"></div>
<template data-stimeo--tags-input-target="tagTemplate">
<li class="tags-input__tag" role="listitem" data-stimeo--tags-input-target="tag">
<span data-tags-input-slot="label"></span>
<%# Removal is handled by a delegated listener on the tags container, so it
works instantly without waiting on Stimulus wiring a data-action onto the
dynamically-added button. %>
<button
type="button"
class="tags-input__remove"
tabindex="-1">×</button>
</li>
</template>
</div>
/*
* Presentation-only styles for the tags-input demo.
* The library handles creating/removing tags, syncing the hidden field, and
* roving (tabindex). data-stimeo--tags-input-full (set when max is reached) is
* the hook used here to dim the input.
*/
.tags-input {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem;
max-width: 28rem;
padding: 0.4rem;
border: 1px solid var(--border-strong);
border-radius: 0.5rem;
background: var(--surface, var(--surface-card));
}
.tags-input__tags {
display: contents;
margin: 0;
padding: 0;
list-style: none;
}
.tags-input__tag {
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 0.15rem 0.5rem;
border-radius: 999px;
background: var(--vital-100);
color: var(--vital-800);
font-size: 0.8125rem;
}
.tags-input__remove {
display: inline-flex;
border: 0;
background: transparent;
color: inherit;
font: inherit;
line-height: 1;
cursor: pointer;
}
.tags-input__remove:focus-visible {
outline: 2px solid var(--accent, var(--color-primary));
outline-offset: 2px;
border-radius: 50%;
}
.tags-input__input {
flex: 1 1 8rem;
min-width: 8rem;
border: 0;
background: transparent;
font: inherit;
color: var(--fg, var(--color-text));
}
.tags-input__input:focus {
outline: none;
}
.tags-input__help {
flex-basis: 100%;
font-size: 0.75rem;
color: var(--color-text-muted);
}
.tags-input[data-stimeo--tags-input-full] .tags-input__input {
opacity: 0.5;
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--tags-input"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
input
必須
|
タグを入力し確定する前のテキスト欄。 | data-stimeo--tags-input-target="input" |
tags
必須
|
チップ一覧のコンテナ。削除・ナビをここで委譲処理する。 | data-stimeo--tags-input-target="tags" |
tag
|
描画された個々のチップ。data-value にタグ値を持つ。 |
data-stimeo--tags-input-target="tag" |
tagTemplate
|
各チップを生成する複製元の template。 | data-stimeo--tags-input-target="tagTemplate" |
status
|
追加・削除を支援技術へ通知する aria-live 領域。 |
data-stimeo--tags-input-target="status" |
fields
|
タグ集合を name 付き隠し入力として送信用に複製するコンテナ。 | data-stimeo--tags-input-target="fields" |
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
delimiter
|
Enter と並び、入力をタグ確定するキー(既定はカンマ)。 | data-stimeo--tags-input-delimiter-value |
max
|
タグ数の上限。0(既定)で無制限。 | data-stimeo--tags-input-max-value |
allowDuplicates
|
true で重複タグを許可する(既定 false)。 | data-stimeo--tags-input-allow-duplicates-value |
name
|
生成する隠し入力の name(既定 tags[])。 | data-stimeo--tags-input-name-value |
アクション
| 名前 | 説明 | アクション |
|---|---|---|
onKeydown
|
Enter/区切りで確定、空欄 Backspace で末尾削除、ArrowLeft でチップ一覧へ移る。 | stimeo--tags-input#onKeydown |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
change
|
タグ集合が変わるたびに発火。detail に tags 配列を載せる。 | stimeo--tags-input:change |
reject
|
追加が拒否されると発火。detail に値と理由(empty/duplicate/max)を載せる。 | stimeo--tags-input:reject |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
tabindex |
タグ削除ボタン | ロービング: アクティブ=0 / 他=-1(タグ列は 1 タブストップ)。 |
data-stimeo--tags-input-full |
コントローラ要素 | max 到達時に付与(入力抑止の手掛かり)。 |
テキスト |
ステータス | 変化したタグのライブリージョン通知。 |