M
MetricUI
Charts

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

Conversion Funnel
<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.

With Conversion Rates
<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.

Horizontal Funnel
<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.

Onboarding Funnel
<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.

Sales Pipeline

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

PropTypeDescription
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

Chart height in px.

direction
"vertical" | "horizontal"

Funnel layout direction.

interpolation
"smooth" | "linear"

Edge curve interpolation.

spacing
number

Gap between stages in px.

shapeBlending
number

Shape blending factor (0 = rectangles, 1 = smooth funnel).

fillOpacity
number

Fill opacity.

borderWidth
number

Border width.

enableLabel
boolean

Show value labels on each stage.

enableSeparators
boolean

Show separator lines between stages.

showConversionRate
boolean

Show conversion rate percentages between stages.

currentPartSizeExtension
number

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

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

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.