頁面區塊 Sections

手繪筆記定價區塊

筆記本紙張風格的三欄方案卡 React 元件:手繪邊框與勾選記號逐筆描出,推薦方案有手繪圈選標註,月繳/年繳切換時價格補間,舊價格畫上刪除線後淡出。

一個像攤開筆記本的定價區塊。每張方案卡是橫線筆記紙——淡藍灰橫線、左側紅色邊距線、頂端三個活頁孔;邊框不用 CSS border,而是依卡片實際尺寸畫一條帶抖動的 SVG 路徑,進場時一筆一筆描出,接著功能勾逐個描出,最後推薦方案外圍的手繪圈與箭頭、手寫標註才出現。上方像便利貼的月繳/年繳切換,選中格底下的手繪圈會滑過去;切換時價格以補間變化,舊價格浮起、被畫上刪除線再淡出,年繳時並排顯示刪去的原價。筆觸由 seed 決定,同一個 seed 每次渲染都一樣,SSR 與瀏覽器不會對不上。

把這個效果裝進你的專案

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

npx webberui@latest add sketchnote-pricing

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

Playground

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

5
260
編輯中的呼叫預設屬性
<SketchnotePricing/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add https://webberui.com/r/sketchnote-pricing.json

或在 components.json 設定 registries 後,改用 @webberui/sketchnote-pricing 安裝。

使用

import { SketchnotePricing } from "@/components/ui/sketchnote-pricing";

<SketchnotePricing
  eyebrow="方案"
  title="挑一本適合你的筆記本"
  subtitle="年繳等於送你兩個月。"
  plans={[
    {
      id: "starter",
      name: "入門",
      price: { monthly: 0, yearly: 0 },
      features: [
        { label: "每月 3 堂公開課", included: true },
        { label: "完整課程庫", included: false },
      ],
      cta: { label: "免費開始", href: "/signup" },
    },
    {
      id: "plus",
      name: "進階",
      price: { monthly: 290, yearly: 2900 },
      features: [
        { label: "完整課程庫", included: true },
        { label: "講師問答", included: true },
      ],
      cta: { label: "升級進階", onClick: () => console.log("upgrade") },
      recommended: true,
      note: "最多人選",
    },
  ]}
  onBillingChange={(billing) => console.log(billing)}
/>

Props

Prop型別預設值說明
plansSketchnotePricingPlan[]—方案清單,建議三張;窄螢幕直排、md 以上三欄
billing"monthly" | "yearly"—受控的計費週期;未提供時由元件內部管理
defaultBilling"monthly" | "yearly""monthly"非受控模式的初始計費週期
onBillingChange(billing: "monthly" | "yearly") => void—切換計費週期時回呼
currencystring"NT$"價格前的貨幣前綴
yearlyNotestring"省 2 個月"切換器旁的手寫小字,傳空字串可隱藏
eyebrowReactNode—標題上方的小標籤
titleReactNode—主標題,下方描出手繪波浪底線;有提供時作為區塊的 aria-labelledby
subtitleReactNode—副標
seednumber5手繪抖動的亂數種子,同一個值永遠畫出相同筆觸
grainbooleanfalse在紙張上疊一層 feTurbulence 噪點
classNamestring—透傳到最外層 section

SketchnotePricingPlan

欄位型別預設值說明
idstring—方案唯一識別碼
namestring—方案名稱(輕微傾斜,像手寫標題)
descriptionstring—方案簡短說明
price{ monthly: number; yearly: number }—monthly 為每月金額,yearly 為一年總額;年繳低於 12 個月總價時會顯示刪去的原價
features{ label: string; included: boolean }[]—功能清單;included: false 以手繪刪除線與淡色呈現
cta{ label: string; href?: string; onClick?: () => void }—行動按鈕;有 href 時渲染為連結,否則為按鈕
recommendedbooleanfalse推薦方案:卡片微傾、略放大,外圍手繪圈選與箭頭標註
notestring"最多人選"推薦方案旁的手寫標註文字

CSS 變數

變數預設值說明
--wb-sketchnote-pricing-accent#0f766e強調色:勾、圈選、箭頭、底線、推薦方案按鈕
--wb-sketchnote-pricing-accent-dark#2dd4bf深色模式的強調色
--wb-sketchnote-pricing-paper#fffdf5筆記紙底色
--wb-sketchnote-pricing-paper-dark#171717深色模式紙張底色(neutral-900),橫線同時調暗
--wb-sketchnote-pricing-radius14px卡片圓角,手繪邊框也依此值轉角
--wb-sketchnote-pricing-duration260ms描線時間單位:卡框 3 倍、每個勾 1 倍、推薦圈 3 倍

細節

  • 進場順序:區塊捲入視窗後,卡框以 pathLength 從 0 描到 1(時長單位 × 3,卡與卡間隔 120ms),接著每個功能勾描出(單位 × 1,間隔 60ms),全部完成後才描推薦圈與箭頭;緩動統一為 cubic-bezier(0.65, 0, 0.35, 1)。
  • 手繪邊框依卡片實際尺寸以 ResizeObserver 重畫,每段約 48px 加一次 ±1.5px 的垂直抖動,結尾略越過起點,像沒收好的筆。每張卡、每個勾都用 seed 加序號產生自己的筆觸。
  • 滑過卡片時以 spring(stiffness 300、damping 20)上浮 4px,推薦卡轉回水平、其他卡微傾 ±0.6°。
  • 時長單位在掛載時讀取 --wb-sketchnote-pricing-duration,因此 CSS 覆寫同時影響 JS 驅動的描線動畫;執行期改變變數後需重新掛載元件才會生效。

可及性

  • 最外層為 section,有標題時以 aria-labelledby 指向標題;每張方案卡是 article,以 aria-labelledby 指向方案名稱
  • 月繳/年繳切換為 role="radiogroup",選項為 role="radio" 搭配 aria-checked;採 roving tabindex,方向鍵、Home、End 可切換
  • 推薦方案除了視覺圈選,名稱後另有螢幕閱讀器專用的「推薦方案」字樣;不含的功能前綴「不含」
  • 價格變動時以 aria-live="polite" 朗讀最終價格與原價;補間中的數字與所有手繪 SVG 對輔助科技隱藏
  • 使用者系統開啟「減少動態效果」時,所有描線直接完整呈現,價格直接切換不補間,也停用滑過卡片的位移