Skip to content
The Membrane Palette
Contentbeta

Chart

A figure shell (title, legend, caption) and a CSS bar list — single, multi-series or stacked — colored by the validated --color-chart-* palette, with every value printed.

Examples

Single series

Course completion by cohort

  • AI Literacy I82%
  • Prompting for Teachers64%
  • Developers' Lab47%
Learners who finished every module, 2026.
HTML for “Single series”
<figure class="mp-chart" aria-labelledby="chart-completion-title">
  <div class="mp-chart__header">
    <p class="mp-chart__title" id="chart-completion-title">Course completion by cohort</p>
  </div>
  <ul class="mp-chart__bars">
    <li class="mp-chart__row"><span class="mp-chart__label">AI Literacy I</span><span class="mp-chart__track"><span class="mp-chart__fill" style="--mp-chart-value: 82%"></span></span><span class="mp-chart__value">82%</span></li>
    <li class="mp-chart__row"><span class="mp-chart__label">Prompting for Teachers</span><span class="mp-chart__track"><span class="mp-chart__fill" style="--mp-chart-value: 64%"></span></span><span class="mp-chart__value">64%</span></li>
    <li class="mp-chart__row"><span class="mp-chart__label">Developers' Lab</span><span class="mp-chart__track"><span class="mp-chart__fill" style="--mp-chart-value: 47%"></span></span><span class="mp-chart__value">47%</span></li>
  </ul>
  <figcaption class="mp-chart__caption">Learners who finished every module, 2026.</figcaption>
</figure>

Stacked, with legend

Enrollment by format

  • Online
  • Hybrid
  • In person
  • 202440 · 25 · 35%
  • 202552 · 28 · 20%
  • 202661 · 27 · 12%
HTML for “Stacked, with legend”
<figure class="mp-chart" aria-labelledby="chart-format-title">
  <div class="mp-chart__header">
    <p class="mp-chart__title" id="chart-format-title">Enrollment by format</p>
    <ul class="mp-chart__legend">
      <li class="mp-chart__key" data-series="1">Online</li>
      <li class="mp-chart__key" data-series="2">Hybrid</li>
      <li class="mp-chart__key" data-series="3">In person</li>
    </ul>
  </div>
  <ul class="mp-chart__bars">
    <li class="mp-chart__row"><span class="mp-chart__label">2024</span><span class="mp-chart__track"><span class="mp-chart__fill" data-series="1" style="--mp-chart-value: 40%"></span><span class="mp-chart__fill" data-series="2" style="--mp-chart-value: 25%"></span><span class="mp-chart__fill" data-series="3" style="--mp-chart-value: 35%"></span></span><span class="mp-chart__value">40 · 25 · 35%</span></li>
    <li class="mp-chart__row"><span class="mp-chart__label">2025</span><span class="mp-chart__track"><span class="mp-chart__fill" data-series="1" style="--mp-chart-value: 52%"></span><span class="mp-chart__fill" data-series="2" style="--mp-chart-value: 28%"></span><span class="mp-chart__fill" data-series="3" style="--mp-chart-value: 20%"></span></span><span class="mp-chart__value">52 · 28 · 20%</span></li>
    <li class="mp-chart__row"><span class="mp-chart__label">2026</span><span class="mp-chart__track"><span class="mp-chart__fill" data-series="1" style="--mp-chart-value: 61%"></span><span class="mp-chart__fill" data-series="2" style="--mp-chart-value: 27%"></span><span class="mp-chart__fill" data-series="3" style="--mp-chart-value: 12%"></span></span><span class="mp-chart__value">61 · 27 · 12%</span></li>
  </ul>
</figure>

All six series

Learners by region

  • Sudeste
  • Nordeste
  • Sul
  • Norte
  • Centro-Oeste
  • Exterior
  • 2026100%
Shares of 3,214 learners. Legend order matches bar order.
HTML for “All six series”
<figure class="mp-chart" aria-labelledby="chart-palette-title">
  <div class="mp-chart__header">
    <p class="mp-chart__title" id="chart-palette-title">Learners by region</p>
    <ul class="mp-chart__legend">
      <li class="mp-chart__key" data-series="1">Sudeste</li>
      <li class="mp-chart__key" data-series="2">Nordeste</li>
      <li class="mp-chart__key" data-series="3">Sul</li>
      <li class="mp-chart__key" data-series="4">Norte</li>
      <li class="mp-chart__key" data-series="5">Centro-Oeste</li>
      <li class="mp-chart__key" data-series="6">Exterior</li>
    </ul>
  </div>
  <ul class="mp-chart__bars">
    <li class="mp-chart__row"><span class="mp-chart__label">2026</span><span class="mp-chart__track"><span class="mp-chart__fill" data-series="1" style="--mp-chart-value: 38%"></span><span class="mp-chart__fill" data-series="2" style="--mp-chart-value: 22%"></span><span class="mp-chart__fill" data-series="3" style="--mp-chart-value: 16%"></span><span class="mp-chart__fill" data-series="4" style="--mp-chart-value: 9%"></span><span class="mp-chart__fill" data-series="5" style="--mp-chart-value: 8%"></span><span class="mp-chart__fill" data-series="6" style="--mp-chart-value: 7%"></span></span><span class="mp-chart__value">100%</span></li>
  </ul>
  <figcaption class="mp-chart__caption">Shares of 3,214 learners. Legend order matches bar order.</figcaption>
</figure>

Guidance

Most numbers in an education product are "one value per category": completion by cohort, enrollment by format. .mp-chart renders those as horizontal bars from plain HTML — no library, no canvas, readable by screen readers as a list — and gives any richer chart (from a charting library) the same frame: title, legend and caption.

Color rules

The six series colors are a validated categorical palette, not picks: each light and dark step was searched for, then checked for lightness band, chroma floor, color-blind separation between neighbors (worst ΔE 11.5 in OKLab ×100, target ≥ 8), normal-vision separation (≥ 16) and ≥ 3:1 contrast on page and card surfaces. The contrast part is enforced by the token build.

SlotTokenHue
1--color-chart-1terracotta — the brand's lead series
2--color-chart-2teal
3--color-chart-3amber
4--color-chart-4burgundy
5--color-chart-5steel blue
6--color-chart-6green
  • Assign in order, never cycle. A 7th series folds into "Other" or the chart splits into small multiples.
  • Color follows the entity: filtering out a series never repaints the survivors.
  • One series = slot 1 and no legend — the title names it. Don't color bars by their value; bar length already shows it.
  • Scatter, bubble or maps (any two marks can touch): at most 2 series (slots 1–2). Slots 1 and 3 collapse for deuteranopes when they sit side by side.
  • Status meaning (pass/fail, error rate) uses the status tokens (--color-success, --color-error…) with a label, never a chart slot.
  • Text never wears the series color — labels and values stay in text tokens.

Using the palette in a charting library

Read the tokens at runtime so charts follow the theme:

const css = getComputedStyle(chartElement);
const series = [1, 2, 3, 4, 5, 6].map((n) => css.getPropertyValue(`--color-chart-${n}`).trim());
const grid = css.getPropertyValue('--color-border-default').trim();
const axisText = css.getPropertyValue('--color-text-secondary').trim();

tokens/tokens.resolved.json has the same values as plain hex for build-time use. Keep marks thin (2px lines, ≥ 8px markers), gridlines in --color-border-default, one y-axis per chart, and ship a hover tooltip and a table view for plotted charts.

Accessibility

  • Wrap in <figure> labelled by the title; add a <figcaption> for source or definitions.
  • Every bar prints its value, so the list reads correctly as text and nothing depends on color.
  • A legend is required whenever there are two or more series; keep its order equal to the bar order.
  • Under Windows High Contrast, fills switch to the system text color so bars stay visible.

API

Chart classes
ClassKind
.mp-chartroot
.mp-chart__headerpart of .mp-chart
.mp-chart__titlepart of .mp-chart
.mp-chart__legendpart of .mp-chart
.mp-chart__keypart of .mp-chart
.mp-chart__barspart of .mp-chart
.mp-chart__rowpart of .mp-chart
.mp-chart__labelpart of .mp-chart
.mp-chart__trackpart of .mp-chart
.mp-chart__fillpart of .mp-chart
.mp-chart__valuepart of .mp-chart
.mp-chart__captionpart of .mp-chart
Chart attributes
AttributeValues
data-series1 · 2 · 3 · 4 · 5 · 6
Chart component tokens
TokenDefaultLight · dark
--mp-chart-bar0.75rem—
--mp-chart-colorvar(--color-chart-1)#B35530 · #D4724F
--mp-chart-value0%—

Design tokens consumed: --border-width-thin --color-bg-hover --color-chart-1 --color-chart-2 --color-chart-3 --color-chart-4 --color-chart-5 --color-chart-6 --color-text-primary --color-text-secondary --color-text-tertiary --font-sans --leading-small --radius-sm --space-1 --space-2 --space-3 --space-4 --space-6 --text-body --text-small --text-xs --weight-medium --weight-semibold

Source