Funnel
PreviewSVGReads selection
Shows how many reach each step of a process and the conversion from one step to the next.
Playground
Checkout funnel
Sep 7 – Oct 6, 2026
5 steps from Sessions (586,098) to Purchased (18,259), 3.12% overall. Product views 57.0% from previous; Added to cart 18.0% from previous; Checkout 49.1% from previous; Purchased 61.7% from previous.
| Step | Value | From previous step | Of first step |
|---|---|---|---|
| Sessions | 586,098 | — | 100.0% |
| Product views | 334,076 | 57.0% | 57.0% |
| Added to cart | 60,256 | 18.0% | 10.3% |
| Checkout | 29,580 | 49.1% | 5.0% |
| Purchased | 18,259 | 61.7% | 3.1% |
align
<Funnel
data={funnel}
step="step"
value="value"
/>Installation
Funnel is exported from @quartile/react, alongside every other chart and component.
git clone https://github.com/zinnoberHaus/quartileNot on npm yet: build the package from the clone as described in Installation. The preview API may change before publication.
Usage
One row per step, in order. Raw rows work too: values that share a step are summed, and steps keep the order they first appear in.
import { Funnel } from '@quartile/react';
const steps = [
{ step: 'Sessions', value: 586098 },
{ step: 'Added to cart', value: 60256 },
{ step: 'Purchased', value: 18259 },
];
export function Checkout() {
return <Funnel data={steps} step="step" value="value" aria-label="Checkout funnel" />;
}Funnel reads the nearest
<Selection> and does not publish to it. Pass selection={false} to show the unfiltered funnel. See Linked selections.Props
PropTypeDefaultDescription
datarequiredDataInput<R>—One row per step in funnel order, or raw rows (values sharing a step are summed).
steprequiredkeyof R & string—Field naming the step. Steps keep the order they first appear in.
valuerequiredkeyof R & string—Field with the count that reached the step.
formatFormatter—Formats counts. Defaults to integers for plain rows (a field named
value would otherwise be inferred as currency); a dataset's declared format is used as given.align'start' | 'center''start'
start: label and figures on one line, a bar under them with the previous step as a ghost. center: tapering bars centered on one axis, figures under each bar.overallbooleantrueShows the first-to-last conversion under the steps. Defaults to true.
selectionstring | false—Selection to read from. Defaults to the nearest; false opts out.
Frame and state props shared with the charts (11) · ChartBaseProps, ChartStateProps
PropTypeDefaultDescription
heightnumber—Plot height in px. Width always fills the container.
classNamestring——
styleCSSProperties——
aria-labelstring—Accessible name. A summary of the data is generated and rendered as hidden text inside the figure.
view'chart' | 'table'—
table renders the same data as a table, with the same formats, at the chart's size. Large lazy tables expose a data-view control rather than mounting every hidden row.tooltipNotestring—Plain-text context shown with tooltips and included in the accessible chart description.
loadingboolean | string—Shows the loading state at the chart's size, so the layout never jumps.
errorboolean | string | Error | null—Shows the error state. A string or Error becomes the message.
errorCodestring—Shown in the error state; copyable for support.
onRetry() => void——
empty{ title?: string; description?: string; action?: ReactNode }—Title and description for the empty state. Shown when there are no rows.
Accessibility
Keyboard
Tab into the funnel; arrow keys move between steps, Home and End jump.
Screen readers
A summary gives the first and last steps, the overall conversion and each step's conversion from the previous one.
Table fallback
Screen readers always get a table of the plotted values with the same formats.
view="table" shows it at the chart's size.Report an issueBuilt Oct 21, 2026