Funnel
Conversion funnel chart showing value drop-off between stages.
import { Funnel } from "metricui";Use Funnel to visualize conversion pipelines — showing how values decrease through sequential stages like signup flows, sales pipelines, or onboarding processes. Supports vertical and horizontal layouts, smooth and linear interpolation, conversion rate annotations, and the simple data shorthand. For comparing categorical values, use BarChart instead.
Basic Example
<Funnel
data={[
{ id: "visited", label: "Visited", value: 10000 },
{ id: "signed-up", label: "Signed Up", value: 4200 },
{ id: "activated", label: "Activated", value: 2800 },
{ id: "subscribed", label: "Subscribed", value: 1400 },
]}
title="Conversion Funnel"
height={360}
/>Conversion Rates
Enable showConversionRate to display percentage drop-off annotations between each stage.
<Funnel
data={[
{ id: "visited", label: "Visited", value: 10000 },
{ id: "signed-up", label: "Signed Up", value: 4200 },
{ id: "activated", label: "Activated", value: 2800 },
{ id: "subscribed", label: "Subscribed", value: 1400 },
]}
title="With Conversion Rates"
showConversionRate
height={360}
/>Horizontal Layout
Set direction="horizontal" for a left-to-right funnel layout. Works well when horizontal space is plentiful and stage labels are short.
<Funnel
data={[
{ id: "visited", label: "Visited", value: 10000 },
{ id: "signed-up", label: "Signed Up", value: 4200 },
{ id: "activated", label: "Activated", value: 2800 },
{ id: "subscribed", label: "Subscribed", value: 1400 },
]}
title="Horizontal Funnel"
direction="horizontal"
showConversionRate
height={280}
/>Linear Interpolation
Switch from the default smooth curves to sharp linear edges with interpolation="linear". Combine with shapeBlending to control how rectangular vs. tapered the stages appear.
<Funnel
data={[
{ id: "download", label: "Download", value: 8500 },
{ id: "install", label: "Install", value: 7200 },
{ id: "signup", label: "Sign Up", value: 5100 },
{ id: "onboard", label: "Onboarded", value: 3400 },
{ id: "active", label: "Active (7d)", value: 1800 },
]}
title="Onboarding Funnel"
interpolation="linear"
shapeBlending={0.4}
showConversionRate
height={400}
/>Simple Data Format
For quick prototyping, pass a plain key-value object via simpleData instead of the full FunnelDatumInput[] array. Keys become labels and ids are auto-generated.
Nothing to show — try adjusting your filters
<Funnel
simpleData={{
Leads: 5000,
Qualified: 2200,
Proposal: 1100,
Closed: 450,
}}
title="Sales Pipeline"
showConversionRate
height={340}
/>Data States
Every component handles loading, empty, and error states. Pass individual props or use the grouped state prop.
Loading
Error
Failed to load data
// Loading state
<Funnel data={[]} title="Conversion Funnel" loading />
// Error state
<Funnel data={[]} title="Conversion Funnel" error={{ message: "Failed to load" }} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
data* | FunnelDatumInput[] | — | Array of funnel stages with id, label, value, and optional color. |
simpleData | Record<string, number> | — | Simple key-value object like { "Visited": 10000, "Signed Up": 4200 }. Converted to FunnelDatumInput[] internally. data takes precedence. |
title | string | — | Chart card title. |
subtitle | string | — | Chart card subtitle. |
description | string | React.ReactNode | — | Description popover. |
footnote | string | — | Footnote. |
action | React.ReactNode | — | Action slot. |
format | FormatOption | — | Format for values in tooltips and labels. |
height | number | 300 | Chart height in px. |
direction | "vertical" | "horizontal" | "vertical" | Funnel layout direction. |
interpolation | "smooth" | "linear" | "smooth" | Edge curve interpolation. |
spacing | number | 4 | Gap between stages in px. |
shapeBlending | number | 0.66 | Shape blending factor (0 = rectangles, 1 = smooth funnel). |
fillOpacity | number | 1 | Fill opacity. |
borderWidth | number | 0 | Border width. |
enableLabel | boolean | true | Show value labels on each stage. |
enableSeparators | boolean | true | Show separator lines between stages. |
showConversionRate | boolean | false | Show conversion rate percentages between stages. |
currentPartSizeExtension | number | 10 | Hover expansion size in px. |
colors | string[] | — | Stage colors. Default: theme series palette. |
legend | boolean | LegendConfig | — | Legend configuration. |
onPartClick | (part: { id: string; value: number; label: string; percentage: number }) => void | — | Click handler for funnel stages. |
animate | boolean | true | Enable/disable animation. |
variant | CardVariant | — | Card variant. CSS-variable-driven via [data-variant]. |
dense | boolean | — | Compact layout. |
className | string | — | Additional CSS class names. |
classNames | { root?: string; header?: string; chart?: string; legend?: string } | — | Sub-element class name overrides. |
id | string | — | HTML id attribute. |
data-testid | string | — | Test id. |
loading | boolean | — | Loading state. |
empty | EmptyState | — | Empty state. |
error | ErrorState | — | Error state. |
stale | StaleState | — | Stale indicator. |
drillDown | boolean | ((event: { id: string; value: number; label: string; percentage: number }) => React.ReactNode) | — | Enable drill-down on stage click. `true` auto-generates a summary KPI row + filtered DataTable from the chart's source data. Pass a render function for full control over the panel content. Requires DrillDown.Root wrapper. |
drillDownMode | DrillDownMode | "slide-over" | Presentation mode for the drill-down panel. "slide-over" (default) slides from the right, full height. "modal" renders centered and compact. |
Data Shape
interface FunnelDatumInput {
id: string; // Unique identifier
label: string; // Display label
value: number; // Value at this stage
color?: string; // Optional custom color
}
// Simple format alternative:
type SimpleFunnelData = Record<string, number>;
// e.g. { "Visited": 10000, "Signed Up": 4200, "Subscribed": 1400 }Notes
- Uses forwardRef.
- Uses forwardRef — attach a ref to the root div.
- simpleData is converted to FunnelDatumInput[] internally; data takes precedence when non-empty.
- Conversion rate annotations are rendered as a custom SVG layer.
- Tooltips show absolute value and percentage of the first stage's value.
- The onPartClick callback includes a percentage field (relative to first stage).
- drillDown={true} auto-generates a summary KPI row + filtered DataTable from the chart's source data. Pass a render function for custom panel content. Requires DrillDown.Root wrapper.