Feature Section Set
一份特色資料、三種落地版面——不對稱格狀、吸附對照捲動與等寬卡片列,切換 variant 即可套用。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
3
0.08
<FeatureSectionSet />
安裝
npx shadcn@latest add https://webberui.com/r/feature-section-set.json或在 components.json 設定 registries 後,改用 @webberui/feature-section-set 安裝。
安裝依賴後,從 registry JSON(/r/feature-section-set.json 的 files[0].content)複製 feature-section-set.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge圖示為選用,示範中的 Zap、Layers 等來自 lucide-react。
使用
三種版面共用同一份 features 陣列,切換 variant 即可切換樣式:
import { Zap, Layers, Sparkles } from "lucide-react";
import { FeatureSection, type Feature } from "@/components/ui/feature-section-set";
const features: Feature[] = [
{ title: "即開即用", description: "一行指令落地。", icon: <Zap /> },
{ title: "語意化 token", description: "整站語氣一致。", icon: <Layers /> },
{ title: "動畫優先", description: "講究的過場。", icon: <Sparkles /> },
];
<FeatureSection
variant="bento"
eyebrow="為什麼選我們"
title="專為動畫打造"
features={features}
/>三種版面
bento:不對稱格狀。用colSpan/rowSpan(1–4)讓部分特色橫跨或縱跨多格,進場時逐張 stagger 浮現,hover 微微抬起。scroll:吸附對照捲動(Pro)。左側視覺面板吸附(sticky),右側特色隨捲動逐段高亮;面板依進度交叉淡入對應的media,並累積進度指示。每個特色可點擊捲回定位。cards:等寬卡片列。最單純的一列特色卡,同樣具備 stagger 進場與 hover 抬升。
對照捲動與捲動容器
scroll 版面以 useScroll 換算作用中的特色索引。若捲動發生在巢狀 overflow-y: auto 容器(如上方示範)內,傳入該容器的 container ref;預設以視窗為捲動容器:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
<FeatureSection
variant="scroll"
features={features} // 每個特色帶 media 供面板顯示
container={scrollerRef}
stickyTop={16}
/>
</div>版面欄數以容器查詢(@container)決定,寬度取自元件自身而非視窗,因此在窄容器或手機上會自動退回單欄堆疊。
Props
FeatureSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
features | Feature[] | — | 特色資料陣列,三種樣式共用 |
variant | "bento" | "scroll" | "cards" | "bento" | 版面樣式 |
eyebrow | React.ReactNode | — | 標題上方的小標 |
title | React.ReactNode | — | 區塊主標題 |
description | React.ReactNode | — | 區塊描述 |
columns | number | 3 | bento / cards 在寬版面時的欄數(1–4) |
stickyTop | number | 96 | scroll 吸附面板距容器頂端的距離(px) |
container | React.RefObject<HTMLElement | null> | — | scroll 巢狀捲動容器 ref;預設以視窗為捲動容器 |
stagger | number | 0.08 | 卡片進場的逐項間隔(秒) |
once | boolean | true | 只在第一次進入視口時播放進場動畫 |
className | string | — | 附加到最外層 <section> 的 class |
Feature
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
title | React.ReactNode | — | 特色標題 |
description | React.ReactNode | — | 特色描述文字 |
icon | React.ReactNode | — | 標題前的圖示(會自動縮放為 20px) |
media | React.ReactNode | — | scroll 樣式作用中時,吸附面板顯示的視覺內容 |
colSpan | number | 1 | bento 橫向跨欄數(1–4,僅寬版面生效) |
rowSpan | number | 1 | bento 縱向跨列數(1–4,僅寬版面生效) |
id | string | — | 錨點 id,套用在該特色外層容器 |
className | string | — | 附加到該特色卡片/區塊的 class |
細節
- 三種版面共用同一份資料,切換
variant就換版面——特色文案不必為不同區塊重寫 scroll沿用card-stack-scroll的useScroll(container / target)慣例,並以useMotionValueEvent換算作用中索引,僅在索引改變時觸發重繪- 吸附面板以
position: sticky完成(版面而非 scroll 事件驅動),對應media以AnimatePresence交叉淡入 - 欄數與跨格皆走容器查詢(
@container+@lg:變體),響應以元件寬度為準而非視窗寬度
可及性
- 使用者系統開啟「減少動態效果」時,進場、hover、交叉淡入與平滑捲動皆停用,
scroll的吸附版面與作用中對照仍保留(屬版面而非動效) scroll每個特色是原生<button>:鍵盤可聚焦、Enter 觸發捲回定位,作用中項目標記aria-current- 純裝飾的圖示與吸附視覺面板標記
aria-hidden,標題以語意化<h2>/<h3>呈現