Frontend Lab
← 回到所有模式
PE03⌨️ Input · 進階輸入選擇

Multi Select

多選

難度 ★★★★★標籤 multi · chips · 搜尋3 min read

模式簡述

Multi Select:選多個 tag。每選一個變 chip,可移除。search filter、permission 設定常用。

選擇框架⋯

已選 0

|未選任何

Claude Code Prompt

💬 Claude Code Prompt
參考:PE03 multi-select
組件:MultiSelect.tsx

Multi Select:選多個 tag。每選一個變 chip,可移除。search filter、permission 設定常用。

限制:
- chip 過多沒折疊
- 沒做 backspace 刪最後一個
- chip 顏色太多種

完整程式碼

MultiSelect.tsx
"use client";
import { useEffect, useState } from "react";
import { X, ChevronDown } from "lucide-react";

type State = "empty" | "few" | "many";

const OPTIONS = ["React", "Vue", "Svelte", "Solid", "Angular", "Qwik", "Astro", "Remix"];

export function MultiSelect({ state = "few" }: { state?: State }) {
const init =
  state === "empty"
    ? []
    : state === "many"
      ? ["React", "Vue", "Svelte", "Solid", "Angular", "Qwik"]
      : ["React", "Vue"];
const [picked, setPicked] = useState<string[]>(init);
useEffect(() => setPicked(init), [state]);

const visible = picked.slice(0, 3);
const extra = picked.length - visible.length;

return (
  <div className="w-full max-w-md">
    <div className="flex min-h-[40px] flex-wrap items-center gap-1 rounded-md border border-border bg-background/50 px-2 py-1.5">
      {picked.length === 0 && (
        <span className="px-1 text-xs text-muted-foreground">選擇框架⋯</span>
      )}
      {visible.map((p) => (
        <span
          key={p}
          className="inline-flex items-center gap-1 rounded bg-lab-accent/15 px-1.5 py-0.5 text-[11px] text-lab-accent"
        >
          {p}
          <button
            onClick={() => setPicked((prev) => prev.filter((x) => x !== p))}
            className="hover:text-foreground"
          >
            <X className="h-2.5 w-2.5" />
          </button>
        </span>
      ))}
      {extra > 0 && (
        <span className="rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground">
          +{extra}
        </span>
      )}
      <ChevronDown className="ml-auto h-3 w-3 text-muted-foreground" />
    </div>
    <p className="mt-2 font-mono text-[11px] text-muted-foreground">
      已選 {picked.length}
    </p>
  </div>
);
}

何時用

  • ✅ 篩選器(產品分類、tag、技術棧)
  • ✅ 權限、角色多選
  • ✅ 群組成員邀請

何時別用

  • ❌ 最多選 2 個(用 checkbox group)
  • ❌ 順序很重要(chip 不顯示順序,用 reorderable list)
  • ❌ 選項超過 50 個(用搜尋型 combobox)

我踩過的坑

  1. chip 過多沒折疊:選了 20 個,整個輸入框爆炸。> 3 個收成 +N 形式。

  2. 沒做 backspace 刪最後一個:使用者習慣按 backspace 刪 chip,沒做就很卡。

  3. chip 顏色太多種:每個 tag 不同色看起來像彩虹。統一一個 accent 色就好。

相關模式

  • PE01
  • PA06

搜尋

按 ⌘K 隨時開啟