Funnel chart React component for Tailwind CSS v4
v1.0.0Added in 1.0.0
A React funnel chart of conversion: each step's count, its conversion and the drop-off between steps, as aligned bars or a tapered shape.
The bars grow in one step after the other the first time the chart scrolls into view while the counts tick up, and each drop-off chip fades in after its row; when the numbers change, the bars glide to their new length. Every number is printed on the row (step, count, conversion, and between rows the drop-off with how many were lost), so there is nothing to hover. When you pass onValueChange or onStepClick the rows become buttons: click or tap one to select it (the others fade to 55%), click it again to clear. With the keyboard the rows are one tab stop: Up / Down (or Left / Right) move between them, Home / End jump to the first and last, Enter or Space select and Escape clears. In the funnel variant the segments are revealed top to bottom (left to right when horizontal); hover a step, or tap it on a phone, to highlight it and read its value, conversion and drop-off in a readout, drag a finger along the funnel to scrub, tap outside to clear. Tab to the funnel and use the arrow keys, Home / End and PageUp / PageDown to walk the steps, Enter to select and Escape to clear; a live region reads each step. A horizontal funnel stacks top to bottom in containers narrower than 480px.
Funnel chart is a Pro React component in the React chart and stat components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add funnel-chart, together with Chart kit, Motion presets, Tones, UIProvider, useControllableState and 1 more and the npm packages motion and d3-shape.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add funnel-chartFunnel chart is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import FunnelChart from @/components/ui/funnel-chart.
import { FunnelChart } from "@/components/ui/funnel-chart"
const pipeline = [
{ id: "lead", label: "Leads", value: 1240 },
{ id: "qualified", label: "Qualified", value: 620 },
{ id: "proposal", label: "Proposal sent", value: 248 },
{ id: "negotiation", label: "Negotiation", value: 96 },
{ id: "won", label: "Won", value: 41 },
]
export function SalesPipeline() {
return (
<FunnelChart
steps={pipeline}
locale="en-US"
label="Sales pipeline, September 2026"
labels={{
conversion: (pct, { reference }) => `${pct} of ${reference.toLowerCase()}`,
dropoff: (pct, lost) => `${pct} · ${lost} lost`,
}}
onValueChange={(id) => console.log(id)}
/>
)
}Props
steps*FunnelStep[] = { id: string; label: ReactNode; value: number; description?: ReactNode; name?: string; color?: string }[]The steps in order, from the widest to the narrowest. name is the plain-text name when label is not a string; description is a quieter second line; color (a palette slot "series-3", a tone or any CSS color) overrides the fill of that step. Negative values draw as 0.
variantdefault"bars""bars" | "funnel"bars: one aligned row per step with every number printed (the readable default and the phone layout). funnel: a tapered shape of trapezoids with the labels beside it.
orientationdefault"vertical""vertical" | "horizontal"Funnel variant: top to bottom, or left to right with the labels above each step. Horizontal falls back to vertical when the chart is narrower than 480px.
curvedefault"linear""linear" | "smooth"Funnel variant: straight trapezoid sides, or smooth S-curves from one step's width to the next.
baselinedefault"first""first" | "previous"What the conversion percent is measured against: the first step ("3.3% of leads") or the step before it (step-to-step conversion; the first step then shows none).
showConversiondefaulttruebooleanThe conversion percent next to each value.
showDropoffdefaulttruebooleanThe chip between steps: how much of the previous step was lost, in percent and in units. A step larger than the one before shows a gain instead.
dropoffThresholddefault10numberDrop-offs from this percent up are printed in the danger text color; smaller ones and gains stay calm. 0 turns the danger color off (every chip muted).
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"The fill of the bars and segments. Neutral is the foreground ink (black in light mode, white in dark mode).
colordefault""stringAny CSS color for the fill; replaces the tone. Empty uses the tone.
stepColorsdefaultfalsebooleanPaint each step in its own chart palette slot (series-1, series-2...) instead of one tone.
sizedefault"md""sm" | "md" | "lg"Bars: track 8 / 12 / 16px, row spacing and text size. Funnel: 200 / 280 / 360px tall.
radiusdefault"full""none" | "sm" | "md" | "full"The corners of the bars and their tracks (bars variant).
valuestring | nullThe selected step id when you control it: the other steps fade to 55%. null clears.
defaultValuedefault"null"string | nullThe step id selected at first, uncontrolled.
onValueChange(id: string | null) => voidCalled when a step is selected or cleared. Passing it (or onStepClick) turns the rows into buttons.
onStepClick(step: FunnelStep, index: number) => voidCalled when a step is clicked, tapped or activated with Enter / Space, e.g. to open the deals in that stage.
valueFormatdefault"number"ChartValueFormat = "number" | "compact" | "currency" | "percent"How the step values print in the rows, the readout and the table. Percent takes whole numbers (12.4 -> "12,4 %").
currencydefault"USD"stringISO 4217 code for valueFormat currency, printed with the narrow symbol ("$128,450").
decimalsdefault0numberFraction digits for values; auto by magnitude when unset (Auto in the playground): 0 for counts, 1 for percent values.
formatValue(value: number, context: { series: string; kind: "label" | "tooltip" | "table" }) => stringReplaces the built-in value formatting everywhere (series is the step id), e.g. compact dollars on the rows and full amounts in the table.
localedefault""stringLocale for numbers and percents. Empty uses the UIProvider / LocaleProvider locale.
showTooltipdefaulttruebooleanFunnel variant: the readout beside a hovered or keyboard-inspected step (pinned above the chart on touch). Bars print every number and need none.
animateddefaulttruebooleanBars grow and counts tick up on first view, the funnel is revealed top to bottom, and changes glide. Reduced motion always shows the final state.
loadingdefaultfalsebooleanSkeleton rows (or a skeleton funnel) in the shape of the chart.
emptyStateReactNodeReplaces the built-in empty state (shown when steps is empty).
labeldefault""stringAccessible name of the figure (followed by the overall conversion) and caption of its data table. Empty joins the step names.
descriptiondefault""stringA one-sentence takeaway for screen readers ("The biggest loss is at the proposal stage").
labelsPartial<FunnelChartLabels>Strings: empty, loading, inspectHint, selected (appended to the funnel's live readout on the selected step), stepHeader / valueHeader / conversionHeader / dropoffHeader / gainHeader (table and readout), and the functions conversion ((pct, { baseline, reference }) => "50.0% of first"), dropoff ((pct, lost) => "50.0% drop-off, 620 lost"), gain ((pct, gained) => ...), step ((label, value, conversion, change) => the screen reader text) and figure ((label, overall) => ...).
classNamesPartial<Record<FunnelChartSlot, string>>Classes for list, step, header, label, description, value, conversion, track, bar, dropoff (bars), svg, segment, stepLabel, tooltip, inspect (funnel) and table.
Parts
DEFAULT_FUNNEL_CHART_LABELS
constantThe English strings: the shared chart labels plus the keyboard hint, conversion, drop-off and gain lines, each step's spoken sentence and the table headers.
Examples
Funnel shape
variant funnel, vertical and horizontal with smooth sides.
Step to step
baseline previous on a checkout, with a drop-off threshold of 40%.
Step colors
Five recruiting stages, each in its own palette slot.
Money per stage
Pipeline value in compact dollars, brand tone.
Clickable steps
onStepClick opens the deals in that stage (a sheet, bottom on phones).
Gains and zero steps
Re-entries print as a gain; a step at 0 shows 0% and a full drop-off.
Loading and empty
Skeleton rows and the empty state.
Phone, 360px
Selectable rows with the selection held in state.
Files
- components/ui/funnel-chart.tsx
FAQ
Is the React Funnel chart component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Funnel chart?
Run npx wingo-ui@latest add funnel-chart. It also adds the Wingo UI items it builds on (Chart kit, Motion presets, Tones, UIProvider, useControllableState and 1 more) and the npm packages motion and d3-shape. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/funnel-chart.
How does Funnel chart behave on phones?
In the funnel variant the segments are revealed top to bottom (left to right when horizontal); hover a step, or tap it on a phone, to highlight it and read its value, conversion and drop-off in a readout, drag a finger along the funnel to scrub, tap outside to clear.
See also
Used in
More React chart and stat components
Articles using this component
- React Funnel Chart: Conversion, Drop-off and Cohorts
Component guides9 min read