Funnel Chart — Conversion Funnel HTML CSS JS Snippet

Funnel Chart · Charts · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Funnel from centred bars
Each bar is sized by a --w custom property and centred with margin: 0 auto, forming the tapering funnel with no SVG or clip-path.
Readable smallest stage
A min-width keeps even the narrowest stage wide enough to show its label and count, so the funnel base stays legible.
Conversion + drop-off rates
Every stage shows the step conversion above a red drop-off percentage, quantifying exactly where users are lost.
Staggered grow-in
An fn-grow keyframe animates each bar from zero to var(--w) with nth-child delays, so the funnel pours in top to bottom.
Variable-width keyframe
Animating to var(--w) lets one keyframe rule drive every stage regardless of its target width — no per-bar animation needed.
Click-to-focus toggle
focusStage rings the selected bar and dims the rest, then clears on a second click — built from two classes and one function.
Per-stage gradient
Each stage carries --c1/--c2 for its own gradient, giving the funnel a cohesive hue progression down the steps.
Data-light markup
Width, label, count, and rate are all editable inline, so swapping in real funnel data needs no JavaScript changes.

About this UI Snippet

Funnel Chart — Centred Tapering Bars, Stage Conversion Rates & Drop-Off Indicators

Screenshot of the Funnel Chart snippet rendered live

A funnel chart is the clearest way to show how users fall away across the steps of a process — visitors to sign-ups to activated to subscribed. Each stage is narrower than the last, and the shrinking width makes drop-off impossible to miss. This snippet implements a clean, animated funnel in plain HTML, CSS, and vanilla JavaScript: centred tapering bars sized by value, per-stage conversion and drop-off percentages, a staggered grow-in animation on load, and click-to-focus highlighting.

The funnel shape from centred bars

Each stage is a bar whose width is its value as a percentage of the top stage, set via a --w custom property and centred with margin: 0 auto. Because every bar is centred and each is narrower than the one above, the stack naturally forms the symmetric tapering funnel silhouette — no SVG polygons or clip-paths needed. A min-width guarantees even the smallest stage stays wide enough to hold its label and count, so the bottom of the funnel never becomes unreadable.

Two rates per stage: conversion and drop-off

Funnels are only useful if they quantify the fall-off. To the right of each bar, this snippet shows two figures: the step conversion rate (what fraction of the previous stage advanced) and the drop-off below it in red (the percentage lost). Seeing "47%" advance and "−53%" lost on the Subscribed row tells the story at a glance and points analysts straight at the leakiest step. A footer shows the overall end-to-end conversion.

Staggered grow-in animation

On load, each bar animates from width: 0 to its --w target with an fn-grow keyframe, and nth-child animation delays stagger the stages so the funnel "pours" in from top to bottom. The keyframe animates to var(--w), so the same rule works for every stage regardless of its target width. This entrance is what turns a static bar list into a chart that feels alive — and it draws the eye down the funnel in the order the steps actually happen.

Click-to-focus

focusStage adds interactivity: clicking a stage highlights it with a ring and dims the others, so you can isolate one step while presenting. Clicking the same stage again clears the focus. It is a toggle built from two classes — .active on the chosen bar and .dim on the rest — driven by one function, so it stays predictable.

The whole chart is data-light: change a stage's --w, label, count, and rate text to plug in real numbers, or render the stages from an array. Pair this funnel with a bar chart for category breakdowns, a metric card grid for headline KPIs, or a sparkline chart for trends.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out why the bars form a funnel shape on your own. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why centering each progressively-narrower bar with margin auto is what produces the tapering silhouette, and why the fn-grow keyframe can animate every stage with the same rule even though each bar's target width is different. The same assistant can help optimize it — ask whether the nth-child animation-delay approach scales cleanly if the number of stages becomes dynamic instead of a fixed five, or whether focusStage's full class-removal-then-reapply pattern is the cheapest way to implement the toggle. It's also useful for extending the chart: have it add absolute drop-off counts alongside the percentages, a horizontal variant that reads left to right instead of top to bottom, or a way to compare two time periods side by side in the same funnel. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an animated conversion funnel chart in plain HTML, CSS, and JavaScript — no chart library, no SVG polygons or clip-paths for the funnel shape itself.

Requirements:
- A card containing several stacked stage rows (at least five), each row showing a horizontal bar with a name and a count on the left, and a step conversion percentage plus a red drop-off percentage on the right.
- Each bar's width must be expressed as a CSS custom property representing that stage's value as a percentage of the very first stage's value, and every bar must be horizontally centered within its row using auto margins — this centering combined with each successive bar being narrower than the one above must be what visually produces the tapering funnel shape, with no other shape-drawing technique involved. Give bars a minimum width so the narrowest stage never becomes too small to hold its label and count.
- Each bar must carry its own two-color gradient via custom properties so the funnel shows a cohesive but distinct hue progression from the first stage to the last.
- On page load, every bar must animate its width from zero up to its target percentage using one single shared CSS keyframe animation that references the width custom property (so the same keyframe rule works regardless of each bar's specific target width), and successive stages must start this animation with an increasing delay so the bars appear to fill in a staggered top-to-bottom sequence rather than all growing simultaneously.
- Clicking any stage must ring/highlight that stage and dim every other stage to roughly a third opacity, isolating it visually; clicking the same already-active stage again must clear the highlight and restore all stages to full opacity. This toggle must be driven by exactly two CSS classes (one for "active", one for "dim") and a single JavaScript function, not per-stage state variables.
- Show an overall end-to-end conversion rate in a footer beneath the stages.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA "Conversion funnel" card appears and five centred bars (Visitors → Renewed) grow in from top to bottom, forming a tapering funnel.
  2. 2
    Read the stagesEach bar shows its name and count; its width is proportional to the top stage, so the narrowing visualises drop-off.
  3. 3
    Check conversion and lossTo the right of each bar, the step conversion rate sits above the red drop-off percentage (e.g. 47% advanced, −53% lost).
  4. 4
    Click a stageClick any bar — it highlights with a ring and the others dim, letting you focus a single step. Click it again to clear.
  5. 5
    See overall conversionThe footer shows the end-to-end rate (7.25%), the fraction of visitors who reached the final stage.
  6. 6
    Plug in real dataEdit each stage's --w, label, count, and rate text — or render the stages from your analytics array.

Real-world uses

Common Use Cases

Marketing and sales funnels
Visualise visitor → lead → opportunity → customer drop-off. Sit it in a dashboard beside a metric card grid.
Product activation funnels
Track sign-up → activated → retained to find where onboarding leaks; pair with an onboarding tour.
E-commerce checkout funnels
Cart → shipping → payment → purchase conversion, highlighting the step that loses the most buyers before a checkout form.
Recruitment pipelines
Applicants → screened → interviewed → hired as a funnel, showing pass-through rates at each hiring stage.
Support and ticket flows
Opened → triaged → resolved → confirmed, surfacing where tickets stall in the process.
Analytics dashboards
Any multi-step conversion report; combine with a bar chart and sparkline chart for a full panel.

Got questions?

Frequently Asked Questions

Loop your stages array and build each .fn-stage, setting --w to value / stages[0].value * 100 + '%', the count text, and the rate. Compute the step conversion as value / prev.value and the drop-off as 1 − that. Keeping --w relative to the first stage is what produces the correct funnel proportions.

Centring each progressively-narrower bar creates the symmetric funnel silhouette that users instantly recognise as a conversion funnel. Left-aligned bars of decreasing width read as a plain bar chart instead. The margin: 0 auto centring is the single rule that turns bars into a funnel.

Add another line in the .fn-rate column with the lost count (prev.value − value), e.g. "−6,800 users". Many analysts want both the rate and the raw number, since a high percentage on a small stage can matter less than a small percentage on a huge one.

The bars are decorative, so expose the data textually: each stage already shows its name, count, and rate in real text. Add an aria-label per stage summarising it ("Sign-ups: 5,200, 43% of visitors"), and consider an off-screen data table for screen-reader users. Make focusable stages real buttons if click-to-focus is a primary interaction.

In React, map a stages array to bars, compute --w and rates with useMemo, and store the focused index in useState to drive active/dim classes. In Vue, use v-for with :style for --w and a ref for the focused stage. In Angular, *ngFor with [style.--w] and a focused index. The grow keyframe and centring CSS port unchanged.