PA06▸🧩 Compose · 互動組合▸篩選
Filter Sidebar
篩選側欄
難度 ★★★★★標籤 篩選 · tag · 清除3 min read
模式簡述
篩選器最容易被忽略的設計:讓使用者知道目前選了什麼、怎麼清除。 沒有 chips 顯示已選條件,使用者要回頭找哪個 checkbox 打勾。0 結果時要主動提示「放寬條件」, 不要只丟一個空白。
- 結果項目 #1
- 結果項目 #2
- 結果項目 #3
- 結果項目 #4
Claude Code Prompt
參考:PA06 filter-sidebar 技術:React 狀態 + chips 具體行為: - 左側:分組 checkbox(框架、類型、難度) - 右側:已選 chips(每個有 × 可移除)+ 「全部清除」按鈕 - chips 超過 5 個會自動換行 - 0 結果時顯示「沒有符合條件的結果 — 試著放寬篩選條件」 限制: - chips 一定要做,沒有的話使用者不知道目前選了什麼 - 「全部清除」要明顯但不搶眼(border + muted color) - 0 結果要主動建議方向,不要只說「沒結果」
完整程式碼
'use client'
import { useState } from 'react'
import { X } from 'lucide-react'
const OPTIONS = {
框架: ['React', 'Vue', 'Svelte'],
類型: ['動畫', '互動', '資料'],
難度: ['★', '★★', '★★★'],
}
export function FilterSidebar() {
const [selected, setSelected] = useState<string[]>([])
function toggle(v: string) {
setSelected(p => p.includes(v) ? p.filter(x => x !== v) : [...p, v])
}
return (
<div className="grid grid-cols-[180px_1fr] gap-4">
<aside>
{Object.entries(OPTIONS).map(([group, items]) => (
<div key={group}>
<p>{group}</p>
{items.map(it => (
<label key={it}>
<input type="checkbox" checked={selected.includes(it)} onChange={() => toggle(it)} />
{it}
</label>
))}
</div>
))}
</aside>
<div>
{selected.length > 0 && (
<div>
{selected.map(s => (
<span key={s} className="chip">
{s}
<button onClick={() => toggle(s)}><X /></button>
</span>
))}
<button onClick={() => setSelected([])}>全部清除</button>
</div>
)}
{/* 結果列表 */}
</div>
</div>
)
}何時用
- ✅ 電商商品列表(多維度篩選)
- ✅ 文章 / 影片庫(標籤、類型、難度)
- ✅ 後台 dashboard 的多條件過濾
何時別用
- ❌ 資料 < 20 筆(直接看比較快)
- ❌ 只有 1 個篩選維度(用單一 select / segment)
- ❌ 手機優先的介面(用 bottom sheet 或 modal)
我踩過的坑
-
沒有 chips 顯示:使用者不知道目前選了什麼,要回頭數 checkbox。 chips 是必備。
-
「全部清除」做成超大紅色按鈕:太搶眼,使用者誤以為是危險操作。 做成 muted text + hover 變色就夠了。
-
0 結果只顯示空白:使用者以為網頁壞了。要顯示「沒有符合條件的結果 — 試著放寬篩選條件」+ 反白被選最多的 chip 提示可移除。
相關模式
- PA01 Search Match — 搜尋 + 篩選的組合