卡片與網格

Bento Grid

便當網格佈局:卡片 stagger 進場,hover 時聚焦上浮、其餘卡片微降暗。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add bento-grid

還沒有專案,或安裝遇到問題?看快速開始 →

Bento Grid 是用 React、Tailwind CSS 與 Motion 做的便當盒網格(bento grid)佈局元件,由 BentoGrid 與 BentoCard 組成:卡片用 colSpan、rowSpan 跨欄跨列,捲動進入畫面時依序進場,滑鼠移到某張卡片時它會上浮,其他卡片降低透明度。

Playground

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

3
0.08
0
編輯中的呼叫預設屬性
<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型別預設值說明
childrenReact.ReactNode—直接放入 BentoCard 子元件
columnsnumber3欄數(1–6)
staggernumber0.08卡片間進場間隔(秒)
delaynumber0進場前延遲(秒)
oncebooleantrue只在第一次進入視口時播放
classNamestring—附加到網格容器的 class

BentoCard

Prop型別預設值說明
colSpannumber1橫向跨欄數(1–6)
rowSpannumber1縱向跨列數(1–6)
titleReact.ReactNode—卡片標題
descriptionReact.ReactNode—卡片描述
childrenReact.ReactNode—任意自訂內容(圖表、圖片等),置於標題上方
classNamestring—附加到卡片的 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 的話,切到「手動」分頁複製原始碼即可。