トークン入力

@ でファイルや人を追加し、/ でコマンドを実行するプロンプト欄。それぞれが分割できないトークンになり、候補メニューはカーソル位置に開きます。

インストール

このトークン入力コンポーネントは CLI または手動で追加できます:

ダークモード対応:この コンポーネント はBoardUIのセマンティックトークンに合わせて自動で切り替わります。 テーマスイッチの設定.

CLIがコンポーネントのソースと内部の依存ファイルをプロジェクトにコピーし、必要なnpmパッケージをインストールします。

npx boardui@latest add token-input

共有UIパッケージや独自のインポートエイリアスを使う場合は、 インストールパスの設定 をCLIの実行前に設定してください。コピー&ペーストの例は、標準のインポートを使います。

トリガー

トリガーは 1 つの文字と、それが開く候補の組み合わせです。一致は単語の先頭から始まり、boundary: "start" ならプロンプトの先頭だけで始まります。メニューは入力に合わせて絞り込まれ、大文字小文字とアクセントは無視されます。items はデータでも、入力が止まったときにクエリと AbortSignal を受け取るローダーでもかまいません。tone: "accent" はチップをアクセントカラーで描き、emptyState は一致がなくてもメニューを開いたままにします。

import { RiFileCodeLine, RiSearchEyeLine } from "@remixicon/react";import type { TokenSuggestion, TokenTrigger } from "@/components/base/token-input/token-input"; const files: TokenSuggestion[] = [ { id: "app/page.tsx", label: "page.tsx", description: "app", icon: RiFileCodeLine }, { id: "components/sidebar.tsx", label: "sidebar.tsx", description: "components", icon: RiFileCodeLine },]; const triggers: TokenTrigger[] = [ // "@" at any word start, filtered as you type. { char: "@", type: "file", title: "Files", items: files }, // "/" only at the very start, as accent chips. { char: "/", type: "command", title: "Commands", boundary: "start", tone: "accent", items: commands }, // Items from a server: called with the query once typing pauses; a newer query aborts the older one. { char: "#", type: "issue", title: "Issues", emptyState: "No issues match", items: (query, signal) => fetch(`/api/issues?q=${query}`, { signal }).then((r) => r.json()), },];

トークンとテキスト

値はテキストとトークンを順に並べたものです。toText はそれをテキストに書き出し、各トークンを [@label](type:value) として、リクエスト、フォーム、保存した下書きに使えるようにします。fromText はそのテキストをトークンに戻します。コピーも同じテキストを書き出すので、どのトークン入力に貼り付けてもチップが戻ります。独自の形式には codec を渡します。

import { TokenInput, fromText, toText, type TokenInputValue } from "@/components/base/token-input/token-input"; const [value, setValue] = useState<TokenInputValue>([]);// ["Review ", { type: "file", value: "components/sidebar.tsx", label: "sidebar.tsx", id: "t1" }, " please"] toText(value); // "Review [@sidebar.tsx](file:components/sidebar.tsx) please"fromText("Review [@sidebar.tsx](file:components/sidebar.tsx) please"); // the value again <TokenInput aria-label="Message" value={value} onValueChange={setValue} triggers={triggers} />

キーボード

チップはカーソルにとって 1 文字です。入力、IME、スペルチェック、自動修正はブラウザのまま動き、チップに触れる操作はすべてフィールド独自の履歴を通ります。

@, /, …単語の先頭でそのトリガーのメニューを開き、入力で絞り込みます
↑ ↓フォーカスとカーソルをフィールドに残したままハイライトを移動します
Enter, Tabハイライト中の項目をチップとして挿入し、後ろにスペースを入れます
エスケープメニューを閉じ、その一致では閉じたままにします
Ctrl+Space閉じた一致をもう一度開きます
← →1 回の押下でチップをまたぎます
Backspaceカーソルの前のチップを削除します
⌘Z, ⇧⌘Zチップも含めて取り消しとやり直し
エントリーメニューが開いていないときは送信します。Shift+Enter で改行します

トークンの削除

tokenDeletion はチップの隣で Backspace が何をするかを決めます。ref ハンドルを使うと、カーソル位置へのトークン挿入、フォーカス、クリアをコードから行えます。どれも 1 回の取り消しで元に戻せます。

<TokenInput tokenDeletion="whole" /> {/* Backspace removes the chip (default) */}<TokenInput tokenDeletion="select" /> {/* first press selects it, the second removes it */}<TokenInput tokenDeletion="revert" /> {/* the chip turns back into "@label" and its menu reopens */}

コンポーザーパネルで

Pro のコンポーザーパネルも同じ triggers を受け取ります。プロンプトはトークン入力になり、引き続き文字列を送ります。

クレジット

編集と一致のルールは、UI SDK の Token Input と Trigger Menu から Apache License 2.0 のもとでユニットテストごと移植しています。メニューは React Aria の Autocomplete、Menu、Popover を BoardUI のコンパクトなドロップダウンのスタイルで使っています。