Components
Follow a journey from first contact to conversion. Compare the size of each stage, find drop-offs, and keep the exact numbers in view.
npx mario-charts@latest add funnel-chartFive ways to read the same journey.
Each stage narrows toward the next. Read the entry width and exact values.
Waiting for chart space
Hover, tap, or focus a stage to inspect. Use arrows to move, Home/End to jump, Enter to select, and Escape to dismiss. Scroll to reach crowded stages.
Select a stage to see its original observation.
import { FunnelChart } from "@/components/charts/funnel-chart";
const stages = [
{ stage: "Visitors", count: 50000 },
{ stage: "Product views", count: 28000 },
{ stage: "Added to cart", count: 12000 },
{ stage: "Checkout", count: 5500 },
{ stage: "Purchase", count: 2800 },
];
export function Conversion() {
return <FunnelChart data={stages} label="stage" value="count"
variant="tapered" showConversionRates height={400}
ariaLabel="Purchase conversion" />;
}50,000 visitors followed by 28,000 product views means 56% step conversion and 22,000 lost between those observations. The final 2,800 purchases are 5.6% of the first stage. Adding stage counts would count the same journey more than once.
The largest observed stage sets the visual scale. Input order is preserved, so stages can widen when additional people enter a process. The chart reports an increase and a rate above 100%; whether that matches your funnel definition depends on your data.
Tapered and smooth shapes transition from each stage's entry width to the next stage's width. Their areas mix both values. Choose straight, horizontal, or columns for direct size comparison. Zero counts have no painted area, while labels and inspection remain available.
A zero first stage has no defined overall percentage; a zero preceding stage has no defined step rate. Missing counts are errors, not zero. Tooltip rates are nullable, and rawValue preserves the original input. Use data and index to access the original stage when migrating custom inspection.
For a journey that splits into alternative paths and rejoins, use the Sankey Chart with measured connections between nodes.
Typed props for stage values, shapes, conversion, and inspection.
| Prop | Type | Default | Description |
|---|---|---|---|
dataRequired | readonly T[] | — | Stages in process order. Never sorted or aggregated. Values must be finite and nonnegative; numeric strings work. Missing, malformed or negative values produce an actionable error. |
label / valueRequired | keyof T | — | Stage name and measured value keys. Repeated labels retain separate original rows and indices. |
variant | 'tapered' | 'straight' | 'smooth' | 'horizontal' | 'columns' | 'tapered' | Tapered/smooth transition from each stage's width to the next. Straight/horizontal encode value by width; columns by height. All use the largest stage as the visual maximum. |
colors | readonly string[] | — | CSS colors in stage order. Defaults to blue/purple; an empty array uses that palette. Named colors and inherited variables work. |
showValues / showPercentages | boolean | true / true | Display counts and percentages of the first stage. Stages are repeated observations of a process, so their sum is not the denominator. |
showConversionRates | boolean | false | Show the current / previous stage ratio before the current stage. An increase can exceed 100%. Zero denominators produce an undefined rate, displayed as a dash. |
showDropOff | boolean | false | Show signed change from the preceding stage: counts lost, counts gained or no change. Exact values and rates are always available in inspection. |
showConnectors | boolean | true | Subtle links between centered slices or columns. Horizontal bars retain a common baseline and have no connectors. |
gap | number | 12 | Requested nonnegative gap. Row layouts reserve at least 26px for rate/change annotations. Columns reserve spacing for readable stage labels. |
borderRadius | number | 4 | Nonnegative corner radius for straight, horizontal and columns, bounded by the measured shape. Use zero for flat corners. |
height / className | number / string | 400 | Positive stable frame height and outer styles. Crowded rows scroll vertically; columns scroll horizontally to retain readable labels. |
loading / error | boolean / string | null | false / null | Retain data during loading for identical geometry. Missing initial data uses a matching neutral placeholder. Loading, empty and error states keep the same frame. |
animation | boolean | true | Staggered growth from the center, left baseline or bottom baseline. No entrance fade. Focus completes growth; reduced motion is respected. |
valueFormatter | (value: number) => string | — | Format stage values and change magnitudes. Percentages are formatted independently. |
ariaLabel / description | string | 'Funnel chart' | Accessible name and context. One roving tab stop, arrow navigation, Home/End, Escape, and Enter/Space activation. The source table includes zero stages. |
onClick | (item: T, index: number) => void | — | Original row and original index on mouse, touch or keyboard activation, including zero-valued stages. |
tooltipRenderer | TooltipRenderer<FunnelChartTooltipData<T>> | — | Original data/index/rawValue plus parsed value, formattedValue, percentage, conversionRate, previousValue, signed change and color. Rates may be null when undefined or numerically unrepresentable. |