Skip to content
WANCRAFT

G.148Data & Feedback

Funnel Chart

A conversion funnel whose stages re-taper smoothly when data changes, with step conversion, drop-off and overall rate.

NewReactMotionCSSTailwindintermediate

Overview

Funnel Chart draws each stage with a width proportional to its count and joins consecutive stages with a band that carries the step conversion and the number lost. In stepped mode stages are bars and the bands taper between them; in smooth mode each stage tapers straight into the next. Shapes are CSS clip-path trapezoids, so when the data changes every width transitions smoothly while the counts tween to their new values. A header shows overall conversion, or — while you hover, tap or focus a stage — that stage's count, share of the first stage and conversion from the previous one. Stages run top to bottom or left to right, form one tab stop with arrow keys, and a visually hidden table carries every number. Bring your own formatter for counts.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/funnel-chart.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/funnel-chart.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/funnel-chart.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { FunnelChart, type FunnelStage } from "@/components/ui/funnel-chart";

export function FunnelChartExample() {
  const stages: FunnelStage[] = [
    { id: "visit", label: "Visited", value: 24800 },
    { id: "product", label: "Viewed product", value: 11240 },
    { id: "cart", label: "Added to cart", value: 4310 },
    { id: "checkout", label: "Checkout", value: 2120 },
    { id: "paid", label: "Purchased", value: 1380 },
  ];

  return (
    <FunnelChart label="Store funnel, this week" data={stages} />
  );
}

03Props

PropTypeDefaultDescription
data{ id: string; label: string; value: number }[]—Stages in order (required). Pass a new array to transition; ids keep stages stable.
labelstring—Accessible name (required) and caption of the screen-reader table.
orientation"vertical" | "horizontal""vertical"Stages top to bottom, or left to right.
shape"stepped" | "smooth""stepped"Bars joined by drop-off bands, or stages that taper into the next.
showConversionbooleantrueConversion % between consecutive stages.
showDropoffbooleantrueCount lost (and its %) between stages.
showSummarybooleantrueHeader with overall conversion, or the active stage's numbers.
stageSizenumber44Stage thickness in px (vertical); horizontal stages are 4× this tall.
durationnumber700Width and number transition in ms (instant with reduced motion).
accentstring"#FF7448"Stage colour; later stages use lighter mixes of it.
format(value: number) => string—Count formatter (en-US integers by default).

04Features

  • 01Widths proportional to counts with a visible minimum
  • 02Smooth re-taper on data change via CSS clip-path transitions; counts tween with Motion
  • 03Step conversion and drop-off annotations between stages
  • 04Overall conversion header that switches to the hovered or focused stage
  • 05Vertical or horizontal flow; stepped or smooth shapes
motion · tweeninput · hoverinput · clickinput · keyboardinput · focus

05Accessibility

  • Stages are list items in a single tab stop (roving tabindex); arrow keys, Home and End move between them, Escape clears the highlight.
  • Each stage's accessible name holds its count, share of the first stage and conversion from the previous stage.
  • A visually hidden table lists every stage with count, share, conversion and drop-off, plus overall conversion.
  • Decorative shapes, bands and duplicated numbers are aria-hidden; focus rings are visible on every stage.
  • With prefers-reduced-motion widths and numbers change instantly.