Pricing Section
完整定價區塊——標頭、月繳/年繳切換、spring 補間價格與主打方案,內建可展開的常見問題手風琴,一次進場 stagger 浮現。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<PricingSection />
安裝
npx shadcn@latest add https://webberui.com/r/pricing-section.json或在 components.json 設定 registries 後,改用 @webberui/pricing-section 安裝。
安裝依賴後,從 registry JSON(/r/pricing-section.json 的 files[0].content)複製 pricing-section.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge lucide-react使用
import {
PricingSection,
type PricingSectionPlan,
type PricingFaqItem,
} from "@/components/ui/pricing-section";
const plans: PricingSectionPlan[] = [
{
name: "入門",
description: "適合個人 side project",
monthly: 0,
yearly: 0,
features: ["3 個專案", "社群支援", "1GB 儲存空間"],
cta: "免費開始",
},
{
name: "專業",
description: "適合成長中的團隊",
monthly: 24,
yearly: 230,
features: ["無限專案", "優先支援", "50GB 儲存空間", "進階分析"],
highlighted: true,
},
{
name: "企業",
monthly: 60,
yearly: 600,
features: ["專屬客戶經理", "SSO / SAML", "無限儲存空間"],
cta: "聯絡我們",
},
];
const faqs: PricingFaqItem[] = [
{ question: "可以隨時更換方案嗎?", answer: "當然,升級立即生效。" },
{ question: "年繳有折扣嗎?", answer: "切換到年繳最高可省下約 20%。" },
];
<PricingSection
eyebrow="定價"
title="簡單透明的定價"
description="隨團隊成長彈性升級,隨時可取消。"
plans={plans}
faqs={faqs}
currency="$"
onSelectPlan={(plan) => console.log(plan.name)}
/>;計費週期切換由元件內部管理——monthly 與 yearly 各填「該週期的實際金額」即可,折扣標籤自動以年繳相對「月繳 ×12」的節省比例計算。faqs 為選填,提供時於方案下方顯示手風琴;未提供則整個 FAQ 區塊不渲染。
Props
PricingSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
plans | PricingSectionPlan[] | — | 方案清單,並排顯示 |
eyebrow | ReactNode | — | 標頭上方的小標籤 |
title | ReactNode | "選擇適合你的方案" | 區塊主標題 |
description | ReactNode | — | 區塊副標描述 |
faqs | PricingFaqItem[] | — | 常見問題清單,提供時顯示手風琴 |
faqTitle | ReactNode | "常見問題" | 常見問題區塊標題 |
currency | string | "$" | 幣別符號,接在價格數字前 |
defaultCycle | "monthly" | "yearly" | "monthly" | 初始計費週期 |
faqAllowMultiple | boolean | false | 是否允許 FAQ 同時展開多項 |
once | boolean | true | 只在第一次進入視口時播放進場動畫 |
onSelectPlan | (plan) => void | — | 點擊方案 CTA 時觸發,回傳該方案 |
className | string | — | 附加到最外層 <section> 的 class |
PricingSectionPlan
| 欄位 | 型別 | 說明 |
|---|---|---|
name | string | 方案名稱 |
description | string | 方案簡短說明(可選) |
monthly | number | 月繳價格(每月金額) |
yearly | number | 年繳價格(每年金額),用來計算折扣 |
features | string[] | 特色列表,每列前綴一個 Check 圖示 |
highlighted | boolean | 標記為主打方案:卡片放大、高亮並顯示徽章(可選) |
badge | string | 主打徽章文字,預設「最受歡迎」(可選) |
cta | string | CTA 按鈕文字,未指定時為「開始使用」(可選) |
PricingFaqItem
| 欄位 | 型別 | 說明 |
|---|---|---|
question | string | 問題 |
answer | ReactNode | 答案,可為純文字或任意節點 |
細節
- 進場 stagger:方案卡片與 FAQ 區塊以
whileInView觸發,卡片依序淡入上浮,只在進入視口時播放 - 週期切換器:月繳/年繳為 segmented control,選中底塊以 Motion
layoutId共享佈局在兩檔之間 spring 滑動 - 價格 spring 補間:切換週期時,價格以 MotionValue 直接寫入 DOM(不觸發 React re-render)spring 過渡到新值,千分位、捨入到整數
- 折扣標籤:年繳模式下若年繳價低於「月繳 ×12」,於價格下方以
AnimatePresence淡入「年繳省 N%」,置於固定高度插槽不推擠版面 - FAQ 手風琴:以
AnimatePresence對height: auto補間展開/收合,箭頭同步旋轉;預設單開(展開新項自動收合前一項),faqAllowMultiple可切為多開
可及性
- 使用者系統開啟「減少動態效果」時,進場動畫、底塊
layoutId滑動、價格補間、折扣淡入與 FAQ 展開全部停用並直接呈現最終狀態(首渲染與 SSR 一致,掛載後才切換靜態) - 整個區塊以
<section aria-labelledby>綁定主標題;切換器為role="group"帶aria-label,選項以aria-pressed標示目前週期 - 價格區塊帶
aria-label(含幣別、金額與週期),補間中的滾動數字aria-hidden,螢幕閱讀器只朗讀最終值 - FAQ 每項為
aria-expanded/aria-controls按鈕,展開內容為role="region"並以aria-labelledby綁回問題;特色與箭頭圖示皆aria-hidden