Bento Grid
便當網格佈局:卡片 stagger 進場,hover 時聚焦上浮、其餘卡片微降暗。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add bento-gridBento Grid 是用 React、Tailwind CSS 與 Motion 做的便當盒網格(bento grid)佈局元件,由 BentoGrid 與 BentoCard 組成:卡片用 colSpan、rowSpan 跨欄跨列,捲動進入畫面時依序進場,滑鼠移到某張卡片時它會上浮,其他卡片降低透明度。
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<BentoGrid/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
適用情境
- SaaS 首頁的功能總覽區,主打功能用大卡片、次要功能用小卡片
- 產品儀表板或年度回顧頁,把數字、圖表、截圖排在同一個區塊
- 作品集或個人頁的「關於我」區,混排照片、技能與連結
- 不適合:卡片高度不一、內容像瀑布流一樣長短不齊時,改用 Masonry Grid
安裝
npx webberui@latest add https://webberui.com/r/bento-grid.json或在 components.json 設定 registries 後,改用 @webberui/bento-grid 安裝。
使用
import { BentoGrid, BentoCard } from "@/components/ui/bento-grid";
<BentoGrid columns={3}>
<BentoCard colSpan={2} title="特色功能" description="跨兩欄的主打卡片。" />
<BentoCard rowSpan={2} title="跨列卡片" description="縱向佔兩列。" />
<BentoCard title="標題" description="一般卡片。" />
<BentoCard title="自訂內容">
<img src="/chart.png" alt="統計圖表" />
</BentoCard>
</BentoGrid>範例
功能總覽區(固定列高)
網格預設 auto-rows-fr,每列等高。透過 className 傳入 auto-rows-[180px] 可以固定列高,tailwind-merge 會蓋掉預設值。
import { BentoGrid, BentoCard } from "@/components/ui/bento-grid";
export function FeatureBento() {
return (
<BentoGrid columns={4} className="auto-rows-[180px]">
<BentoCard
colSpan={2}
rowSpan={2}
title="即時協作"
description="多人同時編輯,游標與修改即時同步。"
>
<img src="/screens/editor.png" alt="協作編輯器畫面" className="rounded-lg" />
</BentoCard>
<BentoCard title="版本紀錄" description="保留 90 天內的每一次修改。" />
<BentoCard title="權限控管" description="依專案設定檢視、編輯權限。" />
<BentoCard colSpan={2} title="API 與 Webhook" description="串接既有的工作流程。" />
</BentoGrid>
);
}從資料陣列產生卡片
卡片內容來自 CMS 或設定檔時,把跨欄資訊放在資料裡再 map 出來即可。
const stats = [
{ label: "月活躍使用者", value: "48,200", colSpan: 2 },
{ label: "平均回應時間", value: "120 ms" },
{ label: "服務可用率", value: "99.95%" },
{ label: "整合服務", value: "36 個", colSpan: 2 },
];
<BentoGrid columns={3}>
{stats.map((s) => (
<BentoCard key={s.label} colSpan={s.colSpan} description={s.label}>
<p className="text-3xl font-semibold tabular-nums">{s.value}</p>
</BentoCard>
))}
</BentoGrid>每次捲動進入都重播進場
once 設為 false 時,網格每次進入視口都會重新播放進場;stagger 與 delay 調整節奏。
<BentoGrid columns={3} once={false} stagger={0.12} delay={0.2}>
<BentoCard title="資料匯入" description="支援 CSV、Excel 與 Google 試算表。" />
<BentoCard title="自動排程" description="設定每日或每週執行。" />
<BentoCard title="報表匯出" description="一鍵輸出 PDF。" />
</BentoGrid>Props
BentoGrid
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 直接放入 BentoCard 子元件 |
columns | number | 3 | 欄數(1–6) |
stagger | number | 0.08 | 卡片間進場間隔(秒) |
delay | number | 0 | 進場前延遲(秒) |
once | boolean | true | 只在第一次進入視口時播放 |
className | string | — | 附加到網格容器的 class |
BentoCard
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
colSpan | number | 1 | 橫向跨欄數(1–6) |
rowSpan | number | 1 | 縱向跨列數(1–6) |
title | React.ReactNode | — | 卡片標題 |
description | React.ReactNode | — | 卡片描述 |
children | React.ReactNode | — | 任意自訂內容(圖表、圖片等),置於標題上方 |
className | string | — | 附加到卡片的 class |
可及性
- 使用者系統開啟「減少動態效果」時,直接渲染靜態網格,無進場動畫與 hover 位移
- 卡片標題以
<h3>語意標籤呈現,輔助科技可依標題導覽 - hover 降暗僅是視覺提示(opacity 最低 0.7),內容仍保持可讀,且不影響鍵盤操作與焦點
常見問題
可以在 Next.js App Router 使用嗎?
可以。原始碼已經有 "use client",在 Server Component 頁面直接 import 即可。元件在掛載後才切換到「減少動態效果」的靜態版,首次渲染與伺服器輸出一致,不會出現 hydration 錯誤。
怎麼做響應式欄數?
columns 會輸出固定的 grid-cols-N,可以改用 className="grid-cols-1 md:grid-cols-3" 覆寫,tailwind-merge 會移除預設的欄數 class。要注意 colSpan、rowSpan 在所有斷點都生效,小螢幕單欄時跨欄卡片會撐出額外的欄。
BentoCard 一定要放在 BentoGrid 裡嗎?
建議放在裡面。單獨使用時卡片會渲染成靜態的 div,沒有進場與 hover 效果。
怎麼改卡片的外觀?
BentoCard 的 className 會合併到卡片本身(預設是圓角、邊框、白底與深色模式的 neutral 配色),可以直接覆寫背景、邊框或內距。
需要哪些依賴?
motion、clsx、tailwind-merge,以及 @/lib/utils 的 cn。不用 CLI 的話,切到「手動」分頁複製原始碼即可。