Funnel chart

Free · MIT

Funnel whose stage bars grow open one after another on an ordinal ramp, with drop-off chips between stages, conversion from the first stage beside each value, and arrow-key rows.

MarkdownOpen in v0
Open in v0

Installation

$ npx shadcn@latest add https://goodui.dev/r/funnel-chart.json

The file lands in components/goodui/funnel-chart.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/funnel-chart works too.

Usage

import { FunnelChart } from "@/components/goodui/funnel-chart"

export function BookingFunnel() {
  return (
    <FunnelChart
      title="Booking funnel"
      stages={[
        { label: "Visited", value: 12400 },
        { label: "Viewed services", value: 8100 },
        { label: "Picked a slot", value: 3900 },
        { label: "Entered details", value: 2600 },
        { label: "Paid deposit", value: 2150 },
      ]}
    />
  )
}

When to use

Use it for
  • Sequential steps where each loses people: visited → picked a slot → paid.
  • Onboarding or trial flows where the drop-off between two specific steps is the story.
  • Reports where the conversion from the first step should be printed, not hovered for.
Reach for something else
  • Steps that are not ordered or do not lose volume: use bar-chart.
  • A single conversion rate: a stat tile (kpi-trend) says it better.
  • Flows with branches: a funnel is linear by definition.
If you needUse
Classic centered funnelalign="center" (default)
Ranked-list feel with long labelsalign="start" labelWidth={140}
Only the numbersshowDropOff={false} showConversion={false}
Brand huecolor="var(--chart-2)" (the ramp derives from it)

Examples

Start-aligned, green ramp

<FunnelChart title="Trial to paid" stages={trial} align="start" color="var(--chart-2)" labelWidth={136} />

Translated chips

<FunnelChart stages={stages} locale="de-DE" labels={{ dropOff: (p) => `−${p}`, conversion: (p, first) => `${p} von ${first}` }} />

API reference

PropTypeDefault
stages*FunnelStage[]—
title
Chart name for screen readers and the table caption.
React.ReactNode—
color
Base hue of the ordinal ramp (first stage full, later stages lighter).
string"var(--chart-1)"
align
center: symmetric funnel. start: bars aligned to the start side, like a ranked list.
"center" | "start""center"
showDropOff
"−38%" chips between stages.
booleantrue
showConversion
Share of the first stage beside each value.
booleantrue
labelWidth
Width of the label column in px.
number112
rowHeightnumber40
formatIntl.NumberFormatOptions—
localestring"en-US"
formatValue(value: number) => string—
duration
Seconds the first bar takes to grow; each next one starts 0.08 s later.
number0.8
labels
Text for built-in controls and screen readers; pass translations here.
Partial<FunnelChartLabels>—

Also accepts every <div> attribute.

Accessibility

TabFocuses the funnel and highlights the first stage.
ArrowUp / ArrowDownMoves the highlight one stage (Left/Right work too).
Home / EndFirst or last stage.
EscapeClears the highlight.
  • The funnel is role="group" with aria-roledescription="funnel chart" and a summary ("Booking funnel: from 12,400 to 2,150, 17% overall").
  • A screen-reader-only table lists stage, value and conversion from the first stage.
  • The highlighted stage is announced with its value, conversion and the drop-off from the previous stage.
  • Values and conversion percentages are printed beside every row, so no reading depends on hover or color.
  • Stage colors are an ordinal ramp of one hue (first stage full, later stages lighter), so order reads in the color too.

Motion

  • On first view bars scale open from the center (or the start side) over duration (0.8 s, ease [0.16, 1, 0.3, 1]), each stage 80 ms after the previous; the values fade in at 40% and the drop-off chips pop in on a spring (stiffness 420, damping 22) at 55%.
  • Hovering a row tints it with the muted surface and dims the other bars to 55%.
  • Reduced motion: everything appears at once.
  • Plain DOM rows; the only animated properties are transform and opacity.

Notes for AI

Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.

  • stages are in order; the first stage is the 100% reference and bar widths are relative to it.
  • Drop-off chips compare each stage with the previous one; conversion compares with the first.
  • Labels truncate in a fixed labelWidth column; raise it for long stage names.
  • Colors come from the ordinal ramp unless stage.color is set; do not color stages by arbitrary hues.

FAQ

Can a later stage be larger than an earlier one?

Yes; its bar is clipped to the width of the first stage and the drop-off chip shows −0%.

Does it support horizontal funnels?

No; rows read better with long labels and on phones. Use bar-chart for a horizontal layout.

Related