WebberUI

Sieve Filter Grid

篩選沉降網格:被濾掉的項目縮小飛進觸發的篩選 chip,計數徽章同步脈衝,存留項目以 FLIP 重排收攏。

載入預覽⋯

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

3
<SieveFilterGrid />

安裝

npx shadcn@latest add https://webberui.com/r/sieve-filter-grid.json

或在 components.json 設定 registries 後,改用 @webberui/sieve-filter-grid 安裝。

安裝依賴後,從 registry JSON(/r/sieve-filter-grid.jsonfiles[0].content)複製 sieve-filter-grid.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion clsx tailwind-merge

使用

import { SieveFilterGrid } from "@/components/ui/sieve-filter-grid";

<SieveFilterGrid
  columns={3}
  items={projects.map((project) => ({
    id: project.id,
    category: project.type,
    content: <ProjectCard project={project} />,
  }))}
  onFilterChange={(category) => console.log(category)}
/>

每個項目需帶唯一 id(動畫進出配對用)與所屬 category;篩選 chip 未指定 categories 時自動從項目推導,並各自帶計數徽章。

Props

Prop型別預設值說明
itemsSieveFilterGridItem[]網格項目,每項為 { id, category, content }
categoriesstring[]自動推導篩選分類清單,未指定時從 items 的 category 依出現順序去重推導
columnsnumber3網格欄數
allLabelstring"全部"「顯示全部」chip 的文字
onFilterChange(category: string | null) => void篩選變更時觸發,顯示全部時帶入 null
classNamestring附加到最外層容器的 class

細節

  • 因果動畫:一般篩選只是讓項目淡出淡入,看不出「誰造成的」。這裡點擊 chip 時,被濾掉的項目會縮小並飛向那顆 chip——動畫的終點就是動作的起因,視覺上直接回答「項目去哪了、為什麼」
  • 飛行路徑:點擊當下以 getBoundingClientRect 量測每個被濾掉項目與目標 chip 的中心偏移,exit 動畫再 animate 到該偏移並縮至 0.2 倍、淡出,如同被 chip 吸入
  • 徽章脈衝:有項目飛入時,該 chip 的計數徽章在項目抵達時 scale 脈衝一下,強化「被接住」的感覺
  • 記住去向:每個被濾掉的項目會記住是哪顆 chip 接住它;重新顯示時從同一顆 chip 的方向縮放飛回,來回路徑因果一致
  • FLIP 收攏:離場項目以 AnimatePresence mode="popLayout" 先脫離文件流,存留項目立即以 layout FLIP 平滑收攏補位,兩段動畫同時進行
  • 選中 chip 的底塊以 layoutId 在 chip 之間滑動

可及性

  • 使用者系統開啟「減少動態效果」時,飛行、FLIP 與徽章脈衝全部停用,篩選直接切換顯示(DOM 結構與 SSR 一致)
  • 篩選 chip 為原生 <button> 群組(role="group"aria-label),以 aria-pressed 標示選取狀態
  • 鍵盤可 Tab 循序聚焦各 chip,focus-visible 時顯示外框

On this page