資料視覺敘事

漏斗圖

SVG 轉換漏斗 React 元件:分層梯形依序生長進場、層間顯示相對上一層的轉換率小籤、hover 高亮並顯示提示,支援直向與橫向兩種方向,附螢幕閱讀器資料表。

註冊、結帳、試用轉付費這類流程最常用的圖表。每個階段畫成一個對稱梯形,上寬等於上一層的下寬、寬度與數值成正比,數值極小的層仍保留 8% 寬度避免看不見;進場時各層以 120ms 間隔依序生長,數值同步淡入。層與層之間的小籤顯示相對上一層的轉換率,滑過或以鍵盤聚焦某一層時會抬亮並顯示提示(階段名稱、數值、佔首層比例),點擊可選取並觸發 onStageClick。標籤塞不進梯形時自動移到側邊並以引線連回。

把這個效果裝進你的專案

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

npx webberui@latest add funnel-chart

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

Playground

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

6
320
編輯中的呼叫預設屬性
<FunnelChart/>

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

安裝

npx webberui@latest add https://webberui.com/r/funnel-chart.json

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

使用

import { FunnelChart } from "@/components/ui/funnel-chart";

<FunnelChart
  stages={[
    { id: "visit", label: "造訪首頁", value: 12480 },
    { id: "start", label: "開始註冊", value: 6240 },
    { id: "form", label: "填寫資料", value: 4180 },
    { id: "verify", label: "驗證信箱", value: 3050 },
    { id: "setup", label: "完成首次設定", value: 2120 },
  ]}
  orientation="vertical"
  totalLabel="整體轉換率"
  valueFormatter={(v) => `${v.toLocaleString()} 人`}
  onStageClick={(stage) => console.log(stage.label)}
/>

Props

Prop型別預設值說明
stagesFunnelStage[]—各階段資料,直向由上而下、橫向由左而右;通常依數值遞減,不遞減也照畫
orientation"vertical" | "horizontal""vertical"漏斗方向
showConversionbooleantrue是否在層間顯示相對上一層的轉換率小籤
showValuesbooleantrue是否在標籤下方顯示數值
valueFormatter(value: number) => string千分位整數數值格式化函式
totalLabelstring—提供時於圖表上方顯示總轉換率(末層 ÷ 首層),此字串為標題
heightnumber320圖表高度(px);寬度固定為容器 100%
gapnumber6層與層之間的間距(px)
selectedIdstring | null—受控的選取階段 id;未提供時由元件內部管理(非受控)
defaultSelectedIdstring | nullnull非受控模式的初始選取階段
onSelectedChange(id: string | null) => void—選取變動時回呼;再次點擊已選取的層會回傳 null
onStageClick(stage: FunnelStage, index: number) => void—點擊或以鍵盤啟動某一層時回呼
ariaLabelstring"轉換漏斗"圖表的無障礙名稱,用於摘要與資料表標題
classNamestring—透傳到最外層容器

FunnelStage

欄位型別預設值說明
idstring—唯一識別碼,用於 key 與選取狀態
labelstring—階段名稱
valuenumber—該階段數值;負數視為 0
colorstring內建色循環覆寫此層顏色(任何合法 CSS 色值)

另外具名匯出 formatFunnelPercent(ratio):10% 以上取整數、以下保留一位小數,分母為 0 時回傳「—」,方便在圖表外的摘要文字沿用同一套格式。

細節

  • 梯形幾何:第 i 層上寬對應 stages[i].value、下寬對應下一層的數值,因此相鄰兩層的邊緣無縫接續;最後一層沒有下一層,下寬收窄為上寬的 82%。
  • 顏色:預設由主色系深到淺的 6 色循環,可用 stage.color 個別覆寫;層內文字依背景亮度自動切換深色或白色。
  • 轉換率小籤:直向畫在層邊界左側、橫向畫在上方並以細線連到邊界;上升為綠色 ↑、跌破一半為紅色、其餘為中性色。
  • 標籤擺放:先嘗試全部放在梯形內,只要有一層塞不下(寬度或高度不足),才預留側邊空間(直向在右、橫向在下),把塞不下的層改為側邊標籤並畫虛線引線。
  • 寬度跟隨容器:以 ResizeObserver 量測實際像素寬度重算 viewBox,文字維持原本字級,不會隨容器縮放變形;切換方向時會重播生長動畫。

可及性

  • SVG 為 role="img",aria-label 摘要列出每一層的名稱、數值與相對轉換率,另以 aria-describedby 指向一份 sr-only 資料表;每層也帶有 <title>
  • 每層上方覆蓋一顆以 clip-path 裁成梯形的原生 button,可用 Tab 聚焦、方向鍵在各層間移動、Home/End 跳到首尾,Enter 或空白鍵觸發選取;aria-pressed 反映選取狀態
  • 鍵盤聚焦時以 3px 天藍色描邊標示焦點,同時顯示與 hover 相同的提示
  • 使用者系統開啟「減少動態效果」時,各層直接完整顯示、不播放生長與淡入動畫,提示也即時切換