Tag Input
標籤輸入器:Enter/逗號新增膠囊 chip(去空白去重),空輸入時 Backspace 刪最後一個;chip 以 spring 彈入、移除時其餘以 FLIP 收攏補位,IME 組字中不誤觸新增。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
6
<TagInput />
安裝
npx shadcn@latest add https://webberui.com/r/tag-input.json或在 components.json 設定 registries 後,改用 @webberui/tag-input 安裝。
安裝依賴後,從 registry JSON(/r/tag-input.json 的 files[0].content)複製 tag-input.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion lucide-react clsx tailwind-merge使用
import { TagInput } from "@/components/ui/tag-input";
<TagInput
value={["設計", "動畫"]}
onChange={(tags) => console.log(tags)}
maxTags={8}
/>未提供 value 時由元件內部管理狀態(非受控);提供 value 搭配 onChange 則為受控模式。onChange 在新增與移除時都會帶入最新的 string[]。
Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
value | string[] | — | 受控標籤陣列;未提供時由元件內部管理 |
onChange | (tags: string[]) => void | — | 標籤變更時觸發(新增或移除),帶入最新標籤陣列 |
placeholder | string | "新增標籤⋯" | 輸入框的 placeholder 文字 |
maxTags | number | — | 最大標籤數,達到後停止新增 |
disabled | boolean | false | 停用整個輸入器 |
className | string | — | 附加到最外層容器的 class |
細節
- 新增:輸入按 Enter 或逗號即新增一顆 chip,值會先去除前後空白;空字串或與現有標籤完全相等(重複)皆略過,並清空輸入
- 刪除:每顆 chip 帶移除 ×;輸入框為空時按 Backspace 刪除最後一個標籤
- 彈入進場:新標籤以 scale + y 的 spring 從下方彈入排列
- FLIP 收攏:移除時該 chip 縮小退場(
AnimatePresence mode="popLayout"先脫離文件流),其餘 chip 與輸入框同時以 layout FLIP 平滑補位;多標籤時以 flex-wrap 自動換行 - IME 安全:中文等輸入法組字中按 Enter/逗號不會誤觸新增(同時檢查
isComposing與keyCode !== 229,涵蓋 Safari 於compositionend後才發 keydown 的情形) - 上限:設定
maxTags後達到數量即停止新增(既有標籤仍可移除)
可及性
- 使用者系統開啟「減少動態效果」時,彈入與 FLIP 全部停用,狀態直接切換(DOM 結構與 SSR 一致)
- 最外層容器帶
role="group"與aria-label;點空白處會把焦點導向輸入框 - 每顆 chip 的移除鈕為原生
<button>,帶「移除標籤某某」的aria-label,可 Tab 循序聚焦,focus-visible時顯示外框 - 輸入框帶
aria-label,停用時disabled一併套用於移除鈕