Skip to main content

Catalog · Charts

Stacked bar

Shows the shares of a whole in one bar, with a legend that says each name and figure in text.

Fits best: app — a page that shows how a whole is split: statuses, sources, a budget

Example

How this week's parcels ended: the bar shows the shares, the legend says them.

Parcels by status, this week
  • Delivered 62 %
  • In transit 21 %
  • At depot 9 %
  • Delayed 5 %
  • Returned 2 %
  • Lost 1 %

Known issues

None known.

Code

Copy the markup

Bundler
import "@luz-ds/catalog/components/stacked-bar.css";
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/stacked-bar.min.css" integrity="sha384-EawyC0MeY43Ls6Vyna5Wo6tQtAJbKY4vu6C6J930w4veLj3B1yFokJZyIu5APjrV" crossorigin="anonymous">

A stylesheet of @luz-ds/catalog: link components/stacked-bar.css after luz.css.

HTML
<figure class="luz-stacked-bar">
  <figcaption>Parcels by status, this week</figcaption>
  <div class="luz-stacked-bar__bar" aria-hidden="true">
    <span class="luz-stacked-bar__part" style="--v: 62"></span>
    <span class="luz-stacked-bar__part" style="--v: 28"></span>
    <span class="luz-stacked-bar__part" style="--v: 10"></span>
  </div>
  <ul class="luz-stacked-bar__legend">
    <li class="luz-stacked-bar__item"><span class="luz-stacked-bar__name">Delivered</span> <span class="luz-stacked-bar__figure">62 %</span></li>
    <li class="luz-stacked-bar__item"><span class="luz-stacked-bar__name">In transit</span> <span class="luz-stacked-bar__figure">28 %</span></li>
    <li class="luz-stacked-bar__item"><span class="luz-stacked-bar__name">Delayed</span> <span class="luz-stacked-bar__figure">10 %</span></li>
  </ul>
</figure>

Variants and options

OptionEffect
--v
On each part, its weight: the bar always fills its width and a part takes its --v of the sum, so 62, 21 and 9 work as well as .62, .21 and .09
--luz-stacked-bar-color
Another chart colour for a part and its item, such as var(--luz-chart-4)
--luz-stacked-bar-h
The height of the bar

How it works

A figure with two lists of the same shares in the same order. The legend is the data: a name and a figure in text for each share, with a swatch in its colour. The bar is a picture of it, a row of parts that take the width in proportion to their --v, with the surface showing through a thin gap between them.

The series take --luz-chart-1 to --luz-chart-6 in the order of the markup, so up to six shares keep their own colour. Put the largest first and group the smallest as “Other”. The inline style sets only --v. With a strict style-src, set it in a rule of your own.

Without JavaScript

It needs none. Without the stylesheet the figure reads as its caption and the legend, a list of names and figures; the bar is empty.

Keyboard and ARIA

Nothing takes focus. The caption and the legend are text: hide the bar with aria-hidden="true", as in the example.

In forced colors the parts and the swatches of the legend carry the same number, so a part is matched to its item by number. The number may not fit in a very narrow part; the legend is in the same order as the bar.

Contrast and focus are in the Design tab.

Design

When to use

Use it to show how a whole is split, when the parts add up to one total: statuses, sources, shares of a budget.

When not to use

Do not use it to compare many values (use a bar list or a column chart), for more than six shares, or for one share (use a meter).

Do and don't

Do Keep to six shares or fewer, the largest first, the smallest grouped as “Other”: each keeps its own colour and a part wide enough to see.
Don't Draw more than six shares: from the seventh the colours start again, and the thin parts cannot be told apart.

Writing the content

Name the whole and the period in the caption (“Parcels by status, this week”), keep each name to a word or two, and write every figure with its unit. The data and the labels are yours: the component only draws them.

Contrast and focus

Each series is a chart colour on the surface; the six are also told apart from each other by hue and lightness, checked in every mode.

PartColour on backgroundLightDarkHigh contrastNeeds
Series 1 on the page
--luz-chart-1 on --luz-surface-page
5.6:1
7.7:1
14.1:1
3:1
Series 2 on the page
--luz-chart-2 on --luz-surface-page
5.3:1
8.9:1
9.3:1
3:1
Series 3 on the page
--luz-chart-3 on --luz-surface-page
9.6:1
10.6:1
10.9:1
3:1
Series 4 on the page
--luz-chart-4 on --luz-surface-page
9.8:1
6.1:1
6.6:1
3:1
Series 5 on the page
--luz-chart-5 on --luz-surface-page
3.9:1
5.0:1
6.2:1
3:1
Series 6 on the page
--luz-chart-6 on --luz-surface-page
3.7:1
5.4:1
14.7:1
3:1
Series 1 on a card
--luz-chart-1 on --luz-surface
5.9:1
7.2:1
14.1:1
3:1
Name
--luz-text-secondary on --luz-surface-page
6.2:1
7.5:1
19.3:1
4.5:1
Figure
--luz-text-primary on --luz-surface-page
15.8:1
15.1:1
21.0:1
4.5:1

Measured from the token values of each mode, rounded down. Needs is the WCAG 2.2 AA minimum: 4.5:1 for text, 3:1 for focus rings, borders and icons; a quiet decorative part keeps 2:1 against what it is drawn on.

  • Focus: nothing takes it.
  • Not colour alone: every share has its name and figure in text, a gap separates the parts, and in forced colors each part and its item show the same number.

Tokens it uses

The 17 tokens that components/stacked-bar.css reads, by family. Each family links to its page, with the values in every mode. In Figma they are variables with the same names: see Tokens in Figma.

Spacing and sizing
--luz-space-2xs, --luz-space-3xs, --luz-space-md, --luz-space-sm, --luz-space-xs
Typography
--luz-font-mono, --luz-font-sans, --luz-text-sm, --luz-text-xs
Radius
--luz-radius-sm

Keyboard and ARIA are in the Code tab.