資料視覺敘事
漏斗圖
SVG 轉換漏斗 React 元件:分層梯形依序生長進場、層間顯示相對上一層的轉換率小籤、hover 高亮並顯示提示,支援直向與橫向兩種方向,附螢幕閱讀器資料表。
註冊、結帳、試用轉付費這類流程最常用的圖表。每個階段畫成一個對稱梯形,上寬等於上一層的下寬、寬度與數值成正比,數值極小的層仍保留 8% 寬度避免看不見;進場時各層以 120ms 間隔依序生長,數值同步淡入。層與層之間的小籤顯示相對上一層的轉換率,滑過或以鍵盤聚焦某一層時會抬亮並顯示提示(階段名稱、數值、佔首層比例),點擊可選取並觸發 onStageClick。標籤塞不進梯形時自動移到側邊並以引線連回。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add funnel-chartPlayground
即時調整 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 | 型別 | 預設值 | 說明 |
|---|---|---|---|
stages | FunnelStage[] | — | 各階段資料,直向由上而下、橫向由左而右;通常依數值遞減,不遞減也照畫 |
orientation | "vertical" | "horizontal" | "vertical" | 漏斗方向 |
showConversion | boolean | true | 是否在層間顯示相對上一層的轉換率小籤 |
showValues | boolean | true | 是否在標籤下方顯示數值 |
valueFormatter | (value: number) => string | 千分位整數 | 數值格式化函式 |
totalLabel | string | — | 提供時於圖表上方顯示總轉換率(末層 ÷ 首層),此字串為標題 |
height | number | 320 | 圖表高度(px);寬度固定為容器 100% |
gap | number | 6 | 層與層之間的間距(px) |
selectedId | string | null | — | 受控的選取階段 id;未提供時由元件內部管理(非受控) |
defaultSelectedId | string | null | null | 非受控模式的初始選取階段 |
onSelectedChange | (id: string | null) => void | — | 選取變動時回呼;再次點擊已選取的層會回傳 null |
onStageClick | (stage: FunnelStage, index: number) => void | — | 點擊或以鍵盤啟動某一層時回呼 |
ariaLabel | string | "轉換漏斗" | 圖表的無障礙名稱,用於摘要與資料表標題 |
className | string | — | 透傳到最外層容器 |
FunnelStage
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 唯一識別碼,用於 key 與選取狀態 |
label | string | — | 階段名稱 |
value | number | — | 該階段數值;負數視為 0 |
color | string | 內建色循環 | 覆寫此層顏色(任何合法 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 相同的提示
- 使用者系統開啟「減少動態效果」時,各層直接完整顯示、不播放生長與淡入動畫,提示也即時切換