メンション入力
「@」を打つとユーザー候補のドロップダウンが絞り込み表示され、選ぶと藍色のメンションchipとして本文に挿入される。候補は矢印キーで移動、Enterで確定、Escで閉じられる。
プレビュー
入力
操作実際に入力して試せます。
仕様書
- 向く場面
- コメント・チャットで特定の人に通知する入力
- 候補を絞りながら選ばせたいメンション
- 本文中にチップとして挿入したい場面
- 避ける場面
- プレーンテキストしか保存できない入力欄
- 候補が数千件で全件検索できないケース
- 構成要素
- ラベル
- 編集領域
- メンションチップ
- 候補メニュー
- 候補項目
- ヒント
- 持っている状態
- 通常
- フォーカス
- ホバー
- 押下中
- 空
- キーボード
@ で候補が開き、↑↓ で循環移動、Enter で確定、Esc で閉じる。候補は Tab 不可(mousedown で選択し、編集領域の選択範囲を保つ)
- 支援技術
編集領域は role=textbox+aria-multiline+aria-labelledby に aria-expanded/controls/activedescendant を同期。候補は role=listbox/option+aria-selected。チップは contenteditable=false
- 動き
なし
デザインの要点
- 候補は「直前の空白+@」から caret までの文字列で絞る。文中の @ 全部に反応するとメールアドレスで開いてしまう
- 候補の確定は click でなく mousedown で行う。click だと先に blur が起き、置き換える選択範囲が消える
- 確定したチップは contenteditable=false の span にして、直後に NBSP を置いて caret を出す。文字が繋がらない
- 候補が 0 件でも「該当なし」を出して閉じない。急に消えると打ち間違いに気づけない
実装メモ
本文は contenteditable の div で作り、選択範囲(Range)を操作して @クエリ文字列をメンションchip(contenteditable=false の span)に置き換えています。候補選びは blur で選択が消えないよう mousedown で確定します。実ページでは、送信時に chip の textContent や data 属性からユーザーIDを集めてサーバーへ渡してください。
コード(コピーして使えます)
<div class="mention-wrap" id="mWrap">
<span class="m-label" id="mLabel">コメントを書く</span>
<div class="editor-box">
<div class="editor" id="editor" contenteditable="true" role="textbox" aria-multiline="true" aria-labelledby="mLabel" aria-haspopup="listbox" aria-expanded="false" aria-controls="mMenu" data-placeholder="@ でメンション…"></div>
<ul class="m-menu" id="mMenu" role="listbox" aria-label="ユーザー候補" hidden></ul>
</div>
<p class="m-hint">「@」を入力するとメンション候補が開きます(↑↓ / Enter / Esc)</p>
</div>