webdevpuneet.com

Stacked Bar Chart — HTML CSS JS Snippet

Stacked Bar Chart · Charts · Plain HTML, CSS & JS · Live preview

CategoryCharts

Copy & paste

Source Code

<div class="sb-card">
  <div class="sb-head">
    <div>
      <h2 class="sb-title">Revenue by stream</h2>
      <div class="sb-sub">First half · $k</div>
    </div>
    <div class="sb-legend" id="sbLegend"></div>
  </div>
  <div class="sb-plot">
    <div class="sb-chart" id="sbChart"></div>
    <div class="sb-tip" id="sbTip"></div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Data-driven segments
build maps each v value to value / max × H pixels, so every column shares one scale and is directly comparable.
Column-reverse stacking
Segments sit in a flex-direction: column-reverse stack, so the first series anchors the bottom and series pile up in order.
Transform grow-in
Stacks animate with scaleY from a bottom origin and staggered delays — proportions stay intact and it exports cleanly.
Hover breakdown tooltip
Hovering shows each series' value plus the total — the per-segment detail you cannot read precisely off the axis.
Tracked tooltip position
The tooltip centres over the hovered column via offsetLeft + offsetWidth / 2 and translateX(-50%).
Auto-generated legend
The legend renders from the SERIES array, so colours and names stay in sync with the bars automatically.
Single source of truth
DATA and SERIES drive the segments, legend, and tooltips — change one array, everything follows.
Hover feedback
The active column brightens with a filter: brightness so it is clear which bar the tooltip refers to.

About this UI Snippet

Stacked Bar Chart — Multi-Series Segments, Hover Breakdown Tooltip & Staggered Grow-In

Screenshot of the Stacked Bar Chart snippet rendered live

A stacked bar chart shows both the total of each category and how that total breaks down into parts — revenue by stream, traffic by source, hours by project. It is the right chart when the composition matters as much as the magnitude. This snippet builds one from a plain data array in HTML, CSS, and vanilla JavaScript: proportional stacked segments per column, an auto-generated legend, a hover tooltip with the per-series breakdown and total, and a staggered grow-in animation.

Data-driven stacking

build reads a DATA array where each entry has a label and a v array of per-series values, and a SERIES array defining each series' name and colour. It finds the maximum column total across the dataset, then for each column maps every series value to a pixel height (value / max × H) and emits a coloured segment. The segments live in a column-reverse flex stack so the first series sits at the bottom and they pile upward in series order. Because heights are derived from one shared max, every column is on the same scale and comparable at a glance.

Compositor-smooth grow-in

Each stack animates up with a sb-grow keyframe using transform: scaleY from a bottom origin, with a per-column animation-delay so the bars rise left to right. Scaling the whole stack (rather than animating each segment's height) keeps the proportions intact during the animation and runs on the GPU — and, importantly, a transform-based animation survives the Tailwind/React export cleanly, where animating raw height would not.

Hover tooltip with full breakdown

Hovering a column shows a dark tooltip listing each series with its colour swatch and value, plus the column total — the detail a stacked chart needs, since you cannot read individual segment values precisely off the axis. The tooltip is positioned by reading the hovered column's offsetLeft + offsetWidth / 2 and centring over it with a translateX(-50%), so it tracks whichever bar you are on. The hovered column brightens slightly for feedback.

Auto-generated legend

The legend is built from the SERIES array, so adding or recolouring a series updates the chart, the segments, and the legend together from one source of truth. There is nothing to keep in sync by hand.

Swap the DATA and SERIES arrays for your real figures and the chart redraws. Pair this with a bar chart for single-series data, an area chart for trends over time, or a metric card grid for headline KPIs.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA "Revenue by stream" card appears; six stacked bars (Jan–Jun) grow up from the baseline with a legend of three series.
  2. 2
    Read the compositionEach bar stacks Product, Services, and Support segments, so you see both the monthly total and its breakdown.
  3. 3
    Hover a barA tooltip shows each series with its value and the column total, positioned centred over the bar you are on.
  4. 4
    Watch the staggerOn load the bars rise left to right via a scaleY animation, drawing the eye across the time axis.
  5. 5
    Recolour or add a seriesEdit the SERIES array — the legend, segments, and tooltip all update from it.
  6. 6
    Plug in your dataReplace DATA with your own { label, v: [...] } entries; heights auto-scale to the largest column total.

Real-world uses

Common Use Cases

Revenue and sales breakdowns
Show total revenue split by product line or region per period. Pair with a metric card grid for headline totals.
Traffic and channel analytics
Sessions by source (organic, paid, social) stacked per day or week; complements an area chart trend.
Budget and spend composition
Spend by category over months, where the mix matters as much as the total.
Time tracking and capacity
Hours by project or team stacked per week in a dashboard layout.
Survey and rating distributions
Stacked positive/neutral/negative responses per question; pair with a funnel chart for conversion.
Inventory and resource usage
Stock or resource consumption by type over time, with the hover tooltip giving exact per-type figures.

Got questions?

Frequently Asked Questions

Replace the DATA array with your entries ({ label, v: [series1, series2, ...] }) and the SERIES array with your series names and colours — keep the v order matching SERIES. build recomputes the max column total and rescales every segment, so the chart adapts to any values and any number of columns or series.

For grouped (side-by-side) bars, render each series as its own thin bar within the column instead of stacking them, scaling by the max single value rather than the max total. Many dashboards offer a toggle: keep both render paths and swap based on a button, since stacked answers "what's the composition" and grouped answers "how do series compare".

Scale each segment by its share of that column's own total instead of the global max: value / columnTotal × H, so every bar fills the full height and shows proportions rather than absolute magnitude. This is ideal when you care about mix shift over time, not raw totals.

The bars are decorative <div>s, so expose the data textually: add an aria-label to each column summarising it ("June: Product 70, Services 44, Support 26, total 140"), give the chart a role="img" with an overall label, and consider an off-screen data table for screen-reader users. Ensure series are distinguishable beyond colour (the legend and tooltip provide names).

In React, compute the segment heights with useMemo from your data and render columns/segments as styled <div>s; hold the hovered index in useState for the tooltip — no manual DOM building. In Vue, use v-for with :style and a ref for the hovered column. In Angular, *ngFor with [style.height]. The scaleY keyframe and stacking CSS port unchanged.