Funnel chartPro
A tapered conversion funnel with drop-off at every step, a device split that morphs the band, and dots that stream through it.
Checkout funnel
Checkout funnel, last 30 days, all. Visited store 100,000 sessions, Viewed product 61,170 sessions, Added to cart 16,420 sessions, Started checkout 8,400 sessions, Purchased 3,590 sessions. 3.6% reach the last step.
| Step | Mobile | Desktop | Shown total | Kept from previous | Of first step |
|---|---|---|---|---|---|
| Visited store | 68,420 sessions | 31,580 sessions | 100,000 sessions | 100% | 100% |
| Viewed product | 39,710 sessions | 21,460 sessions | 61,170 sessions | 61% | 61% |
| Added to cart | 9,140 sessions | 7,280 sessions | 16,420 sessions | 27% | 16% |
| Started checkout | 4,310 sessions | 4,090 sessions | 8,400 sessions | 51% | 8.4% |
| Purchased | 1,540 sessions | 2,050 sessions | 3,590 sessions | 43% | 3.6% |
- Conversion through a fixed sequence of steps.
- Comparing how two segments convert through the same steps.
- A hero chart on a growth or analytics page where the drop-off is the story.
- Use sankey-flow when people can branch, skip, or loop between steps.
- Use bar-chart for unordered categories.
- Use line-chart for conversion over time.
Installation
Pro source and install commands unlock with a Pro plan.
import { FunnelChart } from "@/registry/components/funnel-chart/funnel-chart"; const segments = [{ key: "mobile", label: "Mobile" }, { key: "desktop", label: "Desktop" }];const stages = [ { key: "visit", label: "Visited store", values: { mobile: 68420, desktop: 31580 } }, { key: "cart", label: "Added to cart", values: { mobile: 9140, desktop: 7280 } }, { key: "purchase", label: "Purchased", values: { mobile: 1540, desktop: 2050 } },]; export function Checkout() { const [view, setView] = useState("total"); return <FunnelChart stages={stages} segments={segments} view={view} label="Checkout funnel" unit="sessions" />;}FunnelChart
A conversion funnel drawn as one smooth tapered band: flat across each step and eased between them, with drop-off at every boundary. Segments can be isolated or split with a 2px gap, and every change morphs the band. Optional dots stream through it and the share that leaves at each step falls out.
stagesRequiredFunnelStage[]–Ordered steps: { key, label, value? , values? }. Use value without segments, values keyed by segment with them.segmentsFunnelSegment[]–Parts of every step, such as devices: { key, label }. Leave it out for one total per step.labelRequiredstring–What is counted. Names the chart, the summary, and the table.unitstring""Noun after counts in the tooltip and table, such as "sessions".view"total" | "split" | string"total""total" draws one band, "split" stacks every segment with a gap, and a segment key isolates it and rescales the band to fill the height.flowbooleantrueDots that stream through the band. Each decides up front where it leaves, so the falling share matches the real drop-off.orientation"auto" | "horizontal" | "vertical""auto"Auto turns the funnel vertical below 420px of container width, with steps listed down the side.heightnumber200Band area thickness in pixels when horizontal.formatValue(value: number) => string–Formats counts. Defaults to compact numbers in headings and full numbers in the tooltip.activeIndexnumber | null–Controlled step in focus.onActiveChange(index: number | null) => void–Called as the step in focus changes.emptyLabelstring"No data"Message when the first step is zero.refRef<HTMLElement>–Forwarded to the figure.classNamestring–Extra class on the figure.- Tab
- Focuses the funnel and reads the first step.
- ArrowRightorArrowDown
- Next step.
- ArrowLeftorArrowUp
- Previous step.
- HomeorEnd
- First or last step.
- Escape
- Clears the reading.
- The chart is a focusable group with a roledescription and instructions; the band, dots, and headings are aria-hidden.
- A polite live region reads the step, its count, the share kept from the previous step, and the share of the first.
- A visually hidden summary and a table list every step per segment with both rates.
- Drop-off uses an arrow glyph and a number, never colour alone.
- Switching views morphs the band from the shape on screen with a spring; the split gap opens and closes with the same spring.
- Counts and rates roll to their new values.
- A soft column and an accent clip glide to the step in focus; the tooltip follows on its own spring and stays inside the chart.
- The band grows out of its centre line the first time it is seen.
- Dots run on a canvas at the display rate, pause off screen and in hidden tabs, and are never drawn with reduced motion, where the morphs also land immediately.
- Horizontal from 420px of container width, vertical below with step names down the right side.
- The tooltip flips and clamps so it never leaves the chart.
- Touch reads steps with a press and drag; the page still scrolls vertically.
- Band paths are rewritten from a single paint function; React does not re-render during morphs.
- Dots are drawn on one canvas and stop when the chart leaves the viewport.
- Around 40 dots are alive at once.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Choose it for ordered steps where each keeps part of the previous one: signup, checkout, onboarding, sales pipeline.
- Pass segments and drive view from a segmented control to compare devices, plans, or channels.
- Keep stage labels short; they wrap to two lines above the band.
- Turn flow off for dense dashboards where motion would distract.
The full library index for assistants is at /llms.txt.