Installation
Theme
Mode

Data viz

Funnel

Stage-by-stage conversion at a glance. Each step shows how many made it through, what share of the top that is, and how much fell away since the last step — for onboarding, sales pipelines, or release readiness. Pure SVG, no dependency.

$npx shadcn@latest add @orbit/funnel

Overview

The classic tapered shape — hover a stage to isolate it.

Activation · last 30 days
Invited1,000 · 100%Signed up720 · 72%28%Activated480 · 48%33.3%Created project300 · 30%37.5%Retained 30d185 · 18.5%38.3%

Variants

The classic tapered funnel reads as a story of narrowing; the bars variant trades the metaphor for a denser, more precise row layout that fits a dashboard column.

variant="funnel"
Invited1,000 · 100%Signed up720 · 72%28%Activated480 · 48%33.3%Created project300 · 30%37.5%Retained 30d185 · 18.5%38.3%
variant="bars"
Invited1,000100%
Signed up72072%
28% drop-off
Activated48048%
33.3% drop-off
Created project30030%
37.5% drop-off
Retained 30d18518.5%
38.3% drop-off

What it reads

Every step carries its absolute count, its conversion from the top of the funnel, and the drop-off since the previous step — the metric that tells you where to focus.

Absolute count
The raw number that reached each stage, formatted with thousands separators.
Conversion %
Share of the very first stage that survived to here — the cumulative pass rate.
Drop-off %
How much was lost versus the previous stage — surfaces the leakiest step.

In context

In a dashboard the bars variant sits comfortably beside its own summary — total entered, overall conversion, and the biggest leak.

Sales pipeline
Q2 · 1,420 leads
13.0% close
Leads1,420100%
Qualified86060.6%
39.4% drop-off
Demo booked43030.3%
50% drop-off
Proposal26018.3%
39.5% drop-off
Closed won18513%
28.8% drop-off
Entered
1,420
leads this quarter
Overall conversion
13.0%
leads → closed won
Biggest leak
−50%
Qualified → Demo booked

Theming

The funnel derives a tonal ramp from a single accent — darkest at the top, lightening as it narrows — so it stays on-brand without per-stage color management.

accent="var(--pri)"
View900100%
Click54060%
Buy21023.3%
accent="var(--acc)"
View900100%
Click54060%
Buy21023.3%
accent={seriesColor(3)}
View900100%
Click54060%
Buy21023.3%

Props

PropTypeDefaultDescription
variant"funnel" | "bars""funnel"Centered trapezoids, or label + track rows for a denser dashboard column.
data{ label: string; value: number }[]Stages in order — each must be a subset of the one above.
accentstring"var(--pri)"Single accent the tonal ramp is derived from (any token or color-mix).
showDropoffbooleantruePrints the −% lost since the previous stage beside each step.
formatValue(v: number) => stringtoLocaleStringFormats the absolute counts.
ariaLabelstringSummary for the funnel svg's role=“img”. Defaults to “N stages, first to last, X% overall conversion”.
…restHTMLAttributes<HTMLDivElement>Forwarded to the root div, including ref and className.

Usage

A funnel implies a strict sequence where each stage is a subset of the one above it — don't use it for unordered categories.

Do

Keep stages strictly nested

Each step must be a subset of the one above — a lead can’t convert without first existing.

Don’t

Compare unrelated categories

Bug types or teams aren’t a funnel. Use a bar chart when order and nesting don’t apply.

Do

Lead with the leak

Point readers at the largest drop-off — that’s the stage with the most to gain.

Don’t

Rely on width alone

The min-width floor keeps labels legible, so always print the value and percent too.

Keyboard & accessibility

The tapered funnel is a labelled image; the bars variant is real text that reads top-to-bottom, and drop-off is always stated in words.

roleimg with a text summary
aria-label“5 stages, 1,000 to 185, 18.5% overall”
ColorDrop-off also stated as text, not just red
OrderStages read top-to-bottom in DOM order