タグインプット
component担当者・タグ・メールアドレスのように、複数の値を 1 つずつ追加・削除して集める入力欄です。追加した値は入力欄の下に、削除ボタン付きのタグとして並べます。入力欄の中へタグを入れる形は支援技術で扱いにくいため採らず、入力欄は普通の インプット、削除ボタンはそれぞれ Tab で止まる普通のボタンにしています。
基本
Enter か「追加」で 1 つずつ追加し、× で削除する。空・重複・上限(5 人)を超える追加は受け付けず、入力欄の真下に理由を出す。追加・削除は aria-live で告知し、削除したらフォーカスを次のタグ(無ければ前・入力欄)へ移す
Enter か「追加」で 1 人ずつ追加(最大 5 人)
<label class="label-control-text" for="assignee">担当者</label> <div class="tag-input"> <div class="tag-input-field"> <input type="text" class="input input-md" id="assignee" aria-describedby="assignee-help" /> <button type="button" class="btn btn-md btn-neutral btn-outline">追加</button> </div> <p class="field-support-text" id="assignee-help">Enter か「追加」で 1 人ずつ追加(最大 5 人)</p> <ul class="tag-list" aria-label="追加した担当者"> <li class="tag"> <span class="tag-label">山田</span> <button type="button" class="tag-remove" aria-label="『山田』を削除"> <svg class="icon" aria-hidden="true"><use href="./icons.svg#lucide-x"></use></svg> </button> </li> </ul> <p class="sr-only" aria-live="polite"></p> <!-- 「『山田』を追加しました」を告知 --> </div>
状態
エラーは入力欄に input-error + aria-invalid、真下に field-error-text。長い値は 1 行で省略する(全文は削除ボタンの名前に含まれる)。削除ボタンの hover / focus は is-hover-preview / is-focus-preview の見本
エラー(重複)
*『山田』はすでに追加されています
削除ボタンの enable / hover / focus・長い値
機能
このコンポーネントの用途
自由に入力する値(担当者・タグ・メールアドレス等)を複数集めるフォームの入力欄。追加した値はタグで見せ、1 つずつ削除できる。
選択肢が決まっているなら checkbox(多ければ select 等の一覧から選ぶ)、値 1 つなら input。
一覧の絞り込みのトグルは filter-chip、状態の表示は badge(どちらも tag ではない)。
使用法
推奨される使い方と、やりがちな NG パターン
OK
- ✓入力欄は input-md +「追加」ボタン(btn-md neutral outline)。Enter でも追加できるようにする。
- ✓追加した値は入力欄の下の ul.tag-list に、追加した順に tag で並べる。
- ✓削除ボタンの aria-label に値を含める(例: 『山田』を削除)。「×」だけだと何を消すか分からない。
- ✓追加・削除の結果は aria-live="polite" の領域で告知する(「『山田』を追加しました」)。
- ✓削除したら、フォーカスを次のタグの削除ボタンへ(無ければ前、1 つも無ければ入力欄へ)移す。
- ✓空・重複・上限を超える追加は受け付けず、入力欄の真下に field-error-text で理由を出す(input-error + aria-invalid)。
- ✓上限があるなら補足(field-support-text)に書き、aria-describedby で入力欄と結ぶ(例: 最大 5 人)。
NG
- ✕入力欄の中(枠の内側)にタグを並べない → 支援技術で扱いにくい。タグは入力欄の下に置く。
- ✕タグの間を矢印キーで移動する作りにしない → 削除ボタンはそれぞれ Tab で止まる普通のボタンにする。
- ✕入力の途中(カンマ・スペース)で自動で追加しない → 意図しない値が増える。Enter か「追加」で確定する。
- ✕タグの中で値を編集させない → 消して入れ直す。
- ✕選択肢が決まっている複数選択に使わない → checkbox。
- ✕一覧の絞り込みに使わない → filter-chip / 見出し行の絞り込み。
- ✕タグの色を値ごとに変えない → 色の意味が生まれ、badge(状態)と紛らわしい。
タグは入力欄の下に並べる
操作のしやすさ入力欄は普通の入力欄のまま。削除ボタンはそれぞれ Tab で止まり、「『山田』を削除」と読まれる。
入力欄の枠の中にタグを入れると、タグへは矢印キーでしか移れず、スクリーンリーダーの操作モードも切り替わる。
追加は Enter か「追加」で確定してから
予測できる動き「山田 佐藤」と打っても、Enter か「追加」を押すまでは入力欄の文字のまま。押したときに 1 つのタグになる。
カンマやスペースを打った瞬間に自動でタグにする。姓と名の間のスペースで分かれるなど、意図しない値が増える。
タグインプットのアクセシビリティ
入力欄の中にタグを入れる複合部品は、キーボード・音声操作・スクリーンリーダーの利用者に問題が多い作りです。relay では入力欄・「追加」ボタン・タグの削除ボタンをすべて普通のフォーム部品にし、特別なキー操作を覚えなくても使えるようにしています。WCAG 2.2 全基準は アクセシビリティ ページを参照。
期待される配慮
Presentation / Adaptability / Interaction / Assistive Technology
タグは入力欄の下に並べ、入力欄と混ざらない。長い値は省略し、全文は削除ボタンの名前で伝える。
タグは折り返して並べ、狭い画面でも横にはみ出さない。
入力欄 →「追加」→ 各タグの削除ボタンの順に Tab で止まる。Enter でも追加できる。削除したらフォーカスが次のタグ(無ければ前・入力欄)へ移る。
一覧は「追加した担当者、リスト、2 項目」と読まれ、削除ボタンは「『山田』を削除、ボタン」。追加・削除すると「『山田』を追加しました」と告知される。
DS が担保する機能
追加実装なしで満たされる
- ✓削除ボタンの押せる範囲は 24×24(WCAG 2.5.8 の最低限)。フォーカスリング(info/600)が全周に出る
- ✓タグの文字(fg/high on neutral/100)と削除アイコン(fg/middle)のコントラストは AA 以上
- ✓強制カラーモードではタグの背景が消えるため、輪郭線で形を示す
実装時の必須対応
プロダクト側で担保する
- !入力欄に label(
<label for>)、タグの一覧(ul)にaria-labelを付ける - !削除ボタンの
aria-labelに値を含める(『山田』を削除)。アイコンはaria-hidden="true" - !追加・削除を
aria-live="polite"の領域で告知し、削除後のフォーカスを次(無ければ前・入力欄)へ移す - !空・重複・上限超えは受け付けず、
input-error+aria-invalidと、入力欄の真下のfield-error-text(aria-describedbyで結ぶ)で理由を伝える
テスト方法
スクリーンリーダー / キーボード / 自動チェック
- SR追加すると「『◯◯』を追加しました」、削除すると「『◯◯』を削除しました」と読まれる。削除ボタンは値の名前付きで読まれる
- キーTab だけで入力欄・追加・各削除ボタンに届く。削除後にフォーカスが迷子にならない(次のタグか入力欄にいる)
- 自動axe / Lighthouse で入力欄の名前・ボタン名・コントラストを確認