Charts

Stacked bar

Bars split into up to five segments, as totals or as shares, vertical or horizontal, with a legend.

Built on
CSS gridsubgridcontainer queries@starting-stylecolor-mix()
Client JavaScript
None
Works without React
Yes, as HTML and CSS
Source, gzipped
3.4 kB
Built from
Chart legend
  • Wk 4191Wk 41
    • Urgent12, 13%
    • High31, 34%
    • Normal48, 53%
  • Wk 4297Wk 42
    • Urgent9, 9%
    • High36, 37%
    • Normal52, 54%
  • Wk 43106Wk 43
    • Urgent17, 16%
    • High28, 26%
    • Normal61, 58%
  • Wk 4483Wk 44
    • Urgent6, 7%
    • High33, 40%
    • Normal44, 53%
  • Wk 45108Wk 45
    • Urgent11, 10%
    • High40, 37%
    • Normal57, 53%
Try its options

Loading its options.

Code
import { StackedBar } from "@/components/equip/stacked-bar";

const weeks = [
  { label: "Wk 41", values: [12, 31, 48] },
  { label: "Wk 42", values: [9, 36, 52] },
  { label: "Wk 43", values: [17, 28, 61] },
  { label: "Wk 44", values: [6, 33, 44] },
  { label: "Wk 45", values: [11, 40, 57] },
];

export default function Demo() {
  return (
    <StackedBar
      label="Support tickets by priority, per week"
      series={["Urgent", "High", "Normal"]}
      data={weeks}
      height={56}
      style={{ width: 216 }}
    />
  );
}
Your versionchange its options in Look, This part
HTMLworks in any framework, with the part's CSS
<figure aria-label="Support tickets by priority, per week. Largest total: Wk 45, 108" class="eq-stacked-bar" data-orientation="vertical" data-totals="shown" style="width:216px;--_h:56px">
  <ul role="list" aria-hidden="true" class="eq-chart-legend eq-stacked-bar-legend" data-orientation="row">
    <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Urgent</span></li>
    <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">High</span></li>
    <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Normal</span></li>
  </ul>
  <ul class="eq-stacked-bar-list" role="list" aria-label="Support tickets by priority, per week">
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Wk 41</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.8425925925925926"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:12"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:31"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:48"></span></span>
      </span>
      <span class="eq-stacked-bar-total">91</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Wk 41</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Urgent</span><span class="eq-chart-legend-value">12, 13%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">High</span><span class="eq-chart-legend-value">31, 34%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Normal</span><span class="eq-chart-legend-value">48, 53%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Wk 42</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.8981481481481481"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:9"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:36"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:52"></span></span>
      </span>
      <span class="eq-stacked-bar-total">97</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Wk 42</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Urgent</span><span class="eq-chart-legend-value">9, 9%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">High</span><span class="eq-chart-legend-value">36, 37%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Normal</span><span class="eq-chart-legend-value">52, 54%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Wk 43</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.9814814814814815"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:17"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:28"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:61"></span></span>
      </span>
      <span class="eq-stacked-bar-total">106</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Wk 43</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Urgent</span><span class="eq-chart-legend-value">17, 16%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">High</span><span class="eq-chart-legend-value">28, 26%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Normal</span><span class="eq-chart-legend-value">61, 58%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Wk 44</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.7685185185185185"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:6"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:33"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:44"></span></span>
      </span>
      <span class="eq-stacked-bar-total">83</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Wk 44</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Urgent</span><span class="eq-chart-legend-value">6, 7%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">High</span><span class="eq-chart-legend-value">33, 40%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Normal</span><span class="eq-chart-legend-value">44, 53%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Wk 45</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:1"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:11"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:40"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:57"></span></span>
      </span>
      <span class="eq-stacked-bar-total">108</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Wk 45</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Urgent</span><span class="eq-chart-legend-value">11, 10%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">High</span><span class="eq-chart-legend-value">40, 37%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Normal</span><span class="eq-chart-legend-value">57, 53%</span></li>
        </ul>
      </span>
    </li>
  </ul>
</figure>

Examples

Shares, horizontal

Percent mode fills every bar so shares compare across channels of very different size; the total stays by each bar.

  • Organic search5,600Organic search
    • Activated56%, 3,120
    • Signed up only33%, 1,840
    • Bounced11%, 640
  • Paid social3,510Paid social
    • Activated28%, 980
    • Signed up only40%, 1,410
    • Bounced32%, 1,120
  • Email2,090Email
    • Activated70%, 1,460
    • Signed up only25%, 520
    • Bounced5%, 110
  • Referral980Referral
    • Activated62%, 610
    • Signed up only30%, 290
    • Bounced8%, 80
Code
import { StackedBar } from "@/components/equip/stacked-bar";

const channels = [
  { label: "Organic search", values: [3120, 1840, 640] },
  { label: "Paid social", values: [980, 1410, 1120] },
  { label: "Email", values: [1460, 520, 110] },
  { label: "Referral", values: [610, 290, 80] },
];

export default function Example() {
  return (
    <StackedBar
      label="Sign-ups by channel and outcome, October"
      series={["Activated", "Signed up only", "Bounced"]}
      data={channels}
      mode="percent"
      orientation="horizontal"
      style={{ maxWidth: 440 }}
    />
  );
}
HTMLworks in any framework, with the part's CSS
<figure aria-label="Sign-ups by channel and outcome, October, as shares of each total. Largest total: Organic search, 5,600" class="eq-stacked-bar" data-orientation="horizontal" data-totals="shown" style="max-width:440px;--_h:120px">
  <ul role="list" aria-hidden="true" class="eq-chart-legend eq-stacked-bar-legend" data-orientation="row">
    <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Activated</span></li>
    <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Signed up only</span></li>
    <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Bounced</span></li>
  </ul>
  <ul class="eq-stacked-bar-list" role="list" aria-label="Sign-ups by channel and outcome, October">
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Organic search</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:1"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:3120"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:1840"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:640"></span></span>
      </span>
      <span class="eq-stacked-bar-total">5,600</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Organic search</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Activated</span><span class="eq-chart-legend-value">56%, 3,120</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Signed up only</span><span class="eq-chart-legend-value">33%, 1,840</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Bounced</span><span class="eq-chart-legend-value">11%, 640</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Paid social</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:1"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:980"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:1410"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1120"></span></span>
      </span>
      <span class="eq-stacked-bar-total">3,510</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Paid social</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Activated</span><span class="eq-chart-legend-value">28%, 980</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Signed up only</span><span class="eq-chart-legend-value">40%, 1,410</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Bounced</span><span class="eq-chart-legend-value">32%, 1,120</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Email</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:1"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:1460"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:520"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:110"></span></span>
      </span>
      <span class="eq-stacked-bar-total">2,090</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Email</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Activated</span><span class="eq-chart-legend-value">70%, 1,460</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Signed up only</span><span class="eq-chart-legend-value">25%, 520</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Bounced</span><span class="eq-chart-legend-value">5%, 110</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Referral</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:1"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:610"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:290"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:80"></span></span>
      </span>
      <span class="eq-stacked-bar-total">980</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Referral</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Activated</span><span class="eq-chart-legend-value">62%, 610</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Signed up only</span><span class="eq-chart-legend-value">30%, 290</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Bounced</span><span class="eq-chart-legend-value">8%, 80</span></li>
        </ul>
      </span>
    </li>
  </ul>
</figure>

Cloud cost by service

Up to five segments; hover or tab to a month to read each service's amount and its share of that month.

  • Jun$9.2KJun
    • Compute$4.2K, 46%
    • Database$2.8K, 31%
    • Storage$1.2K, 13%
    • Network$640, 7%
    • Other$310, 3%
  • Jul$9.6KJul
    • Compute$4.5K, 47%
    • Database$2.9K, 30%
    • Storage$1.2K, 13%
    • Network$700, 7%
    • Other$290, 3%
  • Aug$10.2KAug
    • Compute$4.6K, 45%
    • Database$3.1K, 31%
    • Storage$1.4K, 14%
    • Network$720, 7%
    • Other$330, 3%
  • Sep$10.7KSep
    • Compute$4.9K, 46%
    • Database$3.3K, 31%
    • Storage$1.3K, 12%
    • Network$810, 8%
    • Other$350, 3%
  • Oct$11.5KOct
    • Compute$5.3K, 46%
    • Database$3.5K, 31%
    • Storage$1.5K, 13%
    • Network$830, 7%
    • Other$380, 3%
  • Nov$11.6KNov
    • Compute$5.2K, 45%
    • Database$3.6K, 31%
    • Storage$1.5K, 13%
    • Network$870, 8%
    • Other$410, 4%
Code
import { StackedBar } from "@/components/equip/stacked-bar";

const months = [
  { label: "Jun", values: [4210, 2830, 1190, 640, 310] },
  { label: "Jul", values: [4480, 2910, 1240, 700, 290] },
  { label: "Aug", values: [4630, 3120, 1380, 720, 330] },
  { label: "Sep", values: [4920, 3340, 1310, 810, 350] },
  { label: "Oct", values: [5310, 3520, 1460, 830, 380] },
  { label: "Nov", values: [5180, 3610, 1520, 870, 410] },
];

export default function Example() {
  return (
    <StackedBar
      label="Cloud cost by service, per month"
      series={["Compute", "Database", "Storage", "Network", "Other"]}
      data={months}
      format={{ style: "currency", currency: "USD", notation: "compact", maximumFractionDigits: 1 }}
      height={160}
      style={{ maxWidth: 440 }}
    />
  );
}
HTMLworks in any framework, with the part's CSS
<figure aria-label="Cloud cost by service, per month. Largest total: Nov, $11.6K" class="eq-stacked-bar" data-orientation="vertical" data-totals="shown" style="max-width:440px;--_h:160px">
  <ul role="list" aria-hidden="true" class="eq-chart-legend eq-stacked-bar-legend" data-orientation="row">
    <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span></li>
    <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span></li>
    <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span></li>
    <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span></li>
    <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span></li>
  </ul>
  <ul class="eq-stacked-bar-list" role="list" aria-label="Cloud cost by service, per month">
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Jun</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.7920621225194133"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:4210"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:2830"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1190"></span><span class="eq-stacked-bar-segment" data-series="3" style="flex-grow:640"></span><span class="eq-stacked-bar-segment" data-series="4" style="flex-grow:310"></span></span>
      </span>
      <span class="eq-stacked-bar-total">$9.2K</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Jun</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span><span class="eq-chart-legend-value">$4.2K, 46%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span><span class="eq-chart-legend-value">$2.8K, 31%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span><span class="eq-chart-legend-value">$1.2K, 13%</span></li>
          <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span><span class="eq-chart-legend-value">$640, 7%</span></li>
          <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span><span class="eq-chart-legend-value">$310, 3%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Jul</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.8300258843830889"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:4480"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:2910"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1240"></span><span class="eq-stacked-bar-segment" data-series="3" style="flex-grow:700"></span><span class="eq-stacked-bar-segment" data-series="4" style="flex-grow:290"></span></span>
      </span>
      <span class="eq-stacked-bar-total">$9.6K</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Jul</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span><span class="eq-chart-legend-value">$4.5K, 47%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span><span class="eq-chart-legend-value">$2.9K, 30%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span><span class="eq-chart-legend-value">$1.2K, 13%</span></li>
          <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span><span class="eq-chart-legend-value">$700, 7%</span></li>
          <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span><span class="eq-chart-legend-value">$290, 3%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="start">
      <span class="eq-stacked-bar-label">Aug</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.8783433994823123"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:4630"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:3120"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1380"></span><span class="eq-stacked-bar-segment" data-series="3" style="flex-grow:720"></span><span class="eq-stacked-bar-segment" data-series="4" style="flex-grow:330"></span></span>
      </span>
      <span class="eq-stacked-bar-total">$10.2K</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Aug</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span><span class="eq-chart-legend-value">$4.6K, 45%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span><span class="eq-chart-legend-value">$3.1K, 31%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span><span class="eq-chart-legend-value">$1.4K, 14%</span></li>
          <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span><span class="eq-chart-legend-value">$720, 7%</span></li>
          <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span><span class="eq-chart-legend-value">$330, 3%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Sep</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.9257981018119068"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:4920"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:3340"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1310"></span><span class="eq-stacked-bar-segment" data-series="3" style="flex-grow:810"></span><span class="eq-stacked-bar-segment" data-series="4" style="flex-grow:350"></span></span>
      </span>
      <span class="eq-stacked-bar-total">$10.7K</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Sep</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span><span class="eq-chart-legend-value">$4.9K, 46%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span><span class="eq-chart-legend-value">$3.3K, 31%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span><span class="eq-chart-legend-value">$1.3K, 12%</span></li>
          <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span><span class="eq-chart-legend-value">$810, 8%</span></li>
          <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span><span class="eq-chart-legend-value">$350, 3%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Oct</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:0.9922346850733391"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:5310"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:3520"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1460"></span><span class="eq-stacked-bar-segment" data-series="3" style="flex-grow:830"></span><span class="eq-stacked-bar-segment" data-series="4" style="flex-grow:380"></span></span>
      </span>
      <span class="eq-stacked-bar-total">$11.5K</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Oct</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span><span class="eq-chart-legend-value">$5.3K, 46%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span><span class="eq-chart-legend-value">$3.5K, 31%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span><span class="eq-chart-legend-value">$1.5K, 13%</span></li>
          <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span><span class="eq-chart-legend-value">$830, 7%</span></li>
          <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span><span class="eq-chart-legend-value">$380, 3%</span></li>
        </ul>
      </span>
    </li>
    <li class="eq-stacked-bar-item" tabindex="0" data-side="end">
      <span class="eq-stacked-bar-label">Nov</span>
      <span class="eq-stacked-bar-track" aria-hidden="true">
        <span class="eq-stacked-bar-bar" style="--_v:1"><span class="eq-stacked-bar-segment" data-series="0" style="flex-grow:5180"></span><span class="eq-stacked-bar-segment" data-series="1" style="flex-grow:3610"></span><span class="eq-stacked-bar-segment" data-series="2" style="flex-grow:1520"></span><span class="eq-stacked-bar-segment" data-series="3" style="flex-grow:870"></span><span class="eq-stacked-bar-segment" data-series="4" style="flex-grow:410"></span></span>
      </span>
      <span class="eq-stacked-bar-total">$11.6K</span>
      <span class="eq-stacked-bar-tip">
        <span class="eq-stacked-bar-tip-label">Nov</span>
        <ul role="list" class="eq-chart-legend" data-orientation="column">
          <li class="eq-chart-legend-item" data-series="0"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Compute</span><span class="eq-chart-legend-value">$5.2K, 45%</span></li>
          <li class="eq-chart-legend-item" data-series="1"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Database</span><span class="eq-chart-legend-value">$3.6K, 31%</span></li>
          <li class="eq-chart-legend-item" data-series="2"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Storage</span><span class="eq-chart-legend-value">$1.5K, 13%</span></li>
          <li class="eq-chart-legend-item" data-series="3"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Network</span><span class="eq-chart-legend-value">$870, 8%</span></li>
          <li class="eq-chart-legend-item" data-series="4"><span class="eq-chart-legend-mark" data-mark="square" aria-hidden="true"></span><span class="eq-chart-legend-name">Other</span><span class="eq-chart-legend-value">$410, 4%</span></li>
        </ul>
      </span>
    </li>
  </ul>
</figure>

No data yet

When every value is zero the chart keeps its height and says there is no data, rather than drawing empty bars.

No data

Code
import { StackedBar } from "@/components/equip/stacked-bar";

export default function Example() {
  return (
    <StackedBar
      label="Refunds by reason, this week"
      series={["Duplicate", "Not as described", "Other"]}
      data={[
        { label: "Mon", values: [0, 0, 0] },
        { label: "Tue", values: [0, 0, 0] },
      ]}
      height={80}
      style={{ maxWidth: 320 }}
    />
  );
}
HTMLworks in any framework, with the part's CSS
<figure aria-label="Refunds by reason, this week: no data" class="eq-stacked-bar" data-orientation="vertical" data-totals="shown" style="max-width:320px;--_h:80px">
  <p class="eq-stacked-bar-empty">No data</p>
</figure>

Props

PropTypeDefaultWhat it does
data{ label: string; values: number[] }[]noneOne bar per category, one value per series. Missing and negative values count as zero.
seriesstring[]noneNames the segments, bottom or start first. Up to five; past five the rest are left out.
labelstringnoneNames the figure. The largest total is added to it.
mode"absolute" | "percent""absolute"Absolute stacks to the largest total; percent fills every bar to compare shares.
orientation"vertical" | "horizontal""vertical"Direction the bars grow.
showTotalsbooleantrueShows each total by its bar. When off it is still read.
showLegendbooleantrueShows the legend above the bars.
maxnumbernoneFixes the end of the scale in absolute mode.
heightnumber120Plot height of a vertical chart, in pixels.
formatIntl.NumberFormatOptionsnoneHow values and totals are written.
localestring"en-US"Passed to Intl.NumberFormat.
...restComponentProps<"figure">noneEvery native figure attribute.

Anatomy

root.eq-stacked-barA figure named with the summary; data-orientation and data-totals set the layout.
legend.eq-stacked-bar-legendA Chart legend with square marks.
empty.eq-stacked-bar-emptyShown instead of bars when every value is zero.
list.eq-stacked-bar-list
item.eq-stacked-bar-itemA focusable list item holding one bar.
label.eq-stacked-bar-label
track.eq-stacked-bar-trackDraws the baseline.
bar.eq-stacked-bar-barGrows from the baseline on the spring.
segment.eq-stacked-bar-segmentdata-series sets its ink strength.
total.eq-stacked-bar-total
tip.eq-stacked-bar-tipThe readout: visually hidden until its bar is hovered or focused.
tip label.eq-stacked-bar-tip-label

Keyboard

TabMoves through the bars; each one shows and reads every segment with its value and share.

Notes

  • Segments step down in ink strength in a fixed order and sit 1px apart, and the readout names each one, so none relies on colour alone.
  • Each bar is a list item holding its label, total and every segment as text, so the chart reads without the picture.
  • Each bar is a tab stop, which suits a handful of categories.
  • Renders on the server with no client JavaScript.
  • The horizontal layout uses subgrid; where it is missing, labels, bars and totals still line up within each row but not across rows.

Source

Two files, and they are the whole part. Open either to read it, copy it straight from its bar, or add the part to your loadout and install it with everything else you picked.

components/equip/stacked-bar.tsx122 lines
import type { CSSProperties, ComponentProps } from "react";
import { ChartLegend } from "./chart-legend";
import "./stacked-bar.css";

export type StackedBarDatum = {
  label: string;
  /** One value per series, in the same order. Missing and negative values count as zero. */
  values: number[];
};

export type StackedBarProps = ComponentProps<"figure"> & {
  /** One bar per category, in display order. */
  data: StackedBarDatum[];
  /** Names the segments, bottom or start first. Up to five; past five, the rest are left out. */
  series: string[];
  /** Names the chart, such as "Tickets by priority, per week". The largest total is added to it. */
  label: string;
  /** Absolute stacks to the largest total; percent fills every bar and compares shares. */
  mode?: "absolute" | "percent";
  orientation?: "vertical" | "horizontal";
  /** Shows each bar's total by it. */
  showTotals?: boolean;
  showLegend?: boolean;
  /** Fixes the end of the scale in absolute mode. */
  max?: number;
  /** Height of the plot area in a vertical chart, in pixels. */
  height?: number;
  format?: Intl.NumberFormatOptions;
  locale?: string;
};

const MAX_SERIES = 5;

export function StackedBar({
  data,
  series,
  label,
  mode = "absolute",
  orientation = "vertical",
  showTotals = true,
  showLegend = true,
  max,
  height = 120,
  format,
  locale = "en-US",
  className,
  style,
  ...rest
}: StackedBarProps) {
  const number = new Intl.NumberFormat(locale, format);
  const percent = new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: 0 });
  const names = series.slice(0, MAX_SERIES);
  const rows = data.map((d) => {
    const values = names.map((_, k) => {
      const v = d.values[k];
      return typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
    });
    return { label: d.label, values, total: values.reduce((sum, v) => sum + v, 0) };
  });
  const biggest = rows.reduce<(typeof rows)[number] | undefined>((b, r) => (!b || r.total > b.total ? r : b), undefined);
  const top = mode === "percent" ? 1 : Math.max(max ?? 0, biggest?.total ?? 0);
  const empty = rows.length === 0 || names.length === 0 || !biggest || biggest.total === 0;

  const summary = empty
    ? `${label}: no data`
    : mode === "percent"
      ? `${label}, as shares of each total. Largest total: ${biggest.label}, ${number.format(biggest.total)}`
      : `${label}. Largest total: ${biggest.label}, ${number.format(biggest.total)}`;

  return (
    <figure
      aria-label={summary}
      {...rest}
      className={["eq-stacked-bar", className].filter(Boolean).join(" ")}
      data-orientation={orientation}
      data-totals={showTotals ? "shown" : "hidden"}
      style={{ ...style, "--_h": `${height}px` } as CSSProperties}
    >
      {showLegend && !empty && (
        <ChartLegend className="eq-stacked-bar-legend" items={names.map((name) => ({ label: name }))} aria-hidden="true" />
      )}
      {empty ? (
        <p className="eq-stacked-bar-empty">No data</p>
      ) : (
        <ul className="eq-stacked-bar-list" role="list" aria-label={label}>
          {rows.map((r, i) => (
            <li
              key={`${r.label}-${i}`}
              className="eq-stacked-bar-item"
              tabIndex={0}
              data-side={i >= rows.length / 2 ? "end" : "start"}
            >
              <span className="eq-stacked-bar-label">{r.label}</span>
              <span className="eq-stacked-bar-track" aria-hidden="true">
                <span
                  className="eq-stacked-bar-bar"
                  style={{ "--_v": mode === "percent" ? (r.total > 0 ? 1 : 0) : r.total / (top || 1) } as CSSProperties}
                >
                  {r.values.map((v, k) =>
                    v > 0 ? <span key={k} className="eq-stacked-bar-segment" data-series={k} style={{ flexGrow: v }} /> : null,
                  )}
                </span>
              </span>
              <span className="eq-stacked-bar-total">{number.format(r.total)}</span>
              <span className="eq-stacked-bar-tip">
                <span className="eq-stacked-bar-tip-label">{r.label}</span>
                <ChartLegend
                  orientation="column"
                  items={names.map((name, k) => {
                    const v = r.values[k] ?? 0;
                    const share = r.total > 0 ? percent.format(v / r.total) : percent.format(0);
                    return { label: name, value: mode === "percent" ? `${share}, ${number.format(v)}` : `${number.format(v)}, ${share}`, series: k };
                  })}
                />
              </span>
            </li>
          ))}
        </ul>
      )}
    </figure>
  );
}
components/equip/stacked-bar.css326 lines
@layer equip {
  .eq-stacked-bar {
    display: grid;
    gap: var(--eq-space-3);
    width: 100%;
    min-width: 0;
    margin: 0;
    font: var(--eq-weight) var(--eq-text-xs) / 1.3 var(--eq-font);
    color: var(--eq-ink-2);
  }

  /* The series steps, the same as Chart legend's square marks. */
  .eq-stacked-bar [data-series] {
    --_tone: var(--eq-chart-1);
  }

  .eq-stacked-bar [data-series="1"] {
    --_tone: var(--eq-chart-2);
  }

  .eq-stacked-bar [data-series="2"] {
    --_tone: var(--eq-chart-3);
  }

  .eq-stacked-bar [data-series="3"] {
    --_tone: var(--eq-chart-4);
  }

  .eq-stacked-bar [data-series="4"] {
    --_tone: var(--eq-chart-5);
  }

  .eq-stacked-bar-empty {
    display: grid;
    place-items: center;
    min-height: var(--_h);
    margin: 0;
    border-block-end: 1px solid var(--eq-line-strong);
    color: var(--eq-ink-3);
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-empty {
    min-height: calc(var(--eq-space-6) * 2);
  }

  .eq-stacked-bar-list {
    margin: 0;
    padding: 0;
    list-style: none;
    container-type: inline-size;
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-list {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr) max-content;
    gap: var(--eq-space-1) var(--eq-space-2);
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-list {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: var(--eq-space-2);
  }

  .eq-stacked-bar-item {
    position: relative;
    display: grid;
    align-items: center;
    min-height: 24px;
    border-radius: var(--eq-radius-s);
    outline: none;
    cursor: default;
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-item {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-item {
    grid-template-rows: auto var(--_h) auto;
    justify-items: center;
    gap: var(--eq-space-1);
    min-width: 0;
    container-type: inline-size;
  }

  .eq-stacked-bar-label {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color var(--eq-dur) var(--eq-ease);
  }

  .eq-stacked-bar-total {
    color: var(--eq-ink);
    font-weight: var(--eq-weight-strong);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-total {
    grid-row: 1;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-track {
    grid-row: 2;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-label {
    grid-row: 3;
  }

  /* A column too narrow for its total (with the gap beside it) keeps it for screen readers only;
     the tooltip still gives every amount. The width is in em, so larger type steps aside sooner. */
  @container (max-width: 2.7em) {
    .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-total {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      padding: 0;
      border: 0;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
  }

  .eq-stacked-bar[data-totals="hidden"] .eq-stacked-bar-total {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .eq-stacked-bar-track {
    position: relative;
    display: block;
    width: 100%;
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-track {
    height: 14px;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-track {
    height: 100%;
  }

  /* The baseline. Between bars it reaches across the gap, so it reads as one axis. */
  .eq-stacked-bar-track::before {
    content: "";
    position: absolute;
    background: var(--eq-line-strong);
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-track::before {
    inset-block: calc(var(--eq-space-1) / -2);
    inset-inline-start: 0;
    width: 1px;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-track::before {
    inset-inline: calc(var(--eq-space-2) / -2);
    bottom: 0;
    height: 1px;
  }

  /* Segments sit 1px apart, so each edge shows on any surface without a drawn border. */
  .eq-stacked-bar-bar {
    position: absolute;
    display: flex;
    gap: 1px;
    overflow: hidden;
    border-radius: calc(var(--eq-radius-s) / 2);
    transition: scale var(--eq-dur-move) var(--eq-spring);
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-bar {
    inset-block: 0;
    inset-inline-start: 0;
    width: calc(var(--_v) * 100%);
    transform-origin: left center;
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-bar {
    left: 50%;
    bottom: 0;
    flex-direction: column-reverse;
    width: min(100%, 28px);
    height: calc(var(--_v) * 100%);
    translate: -50% 0;
    transform-origin: center bottom;
  }

  @starting-style {
    .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-bar {
      scale: 0 1;
    }

    .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-bar {
      scale: 1 0;
    }
  }

  .eq-stacked-bar-segment {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    background: var(--_tone, var(--eq-ink));
  }

  /* The readout. Out of sight it is still text, so a screen reader reads it with its bar. */
  .eq-stacked-bar-tip {
    position: absolute;
    top: 0;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .eq-stacked-bar-tip-label {
    display: block;
    margin-block-end: var(--eq-space-1);
    color: var(--eq-ink);
    font-weight: var(--eq-weight-strong);
  }

  .eq-stacked-bar-item:focus-visible {
    z-index: 1;
    outline: 2px solid var(--eq-focus);
    outline-offset: 2px;
  }

  .eq-stacked-bar-item:focus-visible .eq-stacked-bar-label {
    color: var(--eq-ink);
  }

  .eq-stacked-bar-item:focus-visible .eq-stacked-bar-tip {
    z-index: 1;
    width: max-content;
    max-width: calc(50cqi - var(--eq-space-3));
    height: auto;
    margin: 0;
    padding: var(--eq-space-1) var(--eq-space-2);
    overflow: visible;
    clip-path: none;
    white-space: normal;
    border: 1px solid var(--eq-line-strong);
    border-radius: var(--eq-radius-m);
    background: var(--eq-raised);
    box-shadow: var(--eq-shadow);
    -webkit-backdrop-filter: var(--eq-blur);
    backdrop-filter: var(--eq-blur);
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-item[data-side="start"]:focus-visible .eq-stacked-bar-tip {
    left: calc(50% + var(--eq-space-4) + 2px);
  }

  .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-item[data-side="end"]:focus-visible .eq-stacked-bar-tip {
    right: calc(50% + var(--eq-space-4) + 2px);
  }

  .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-item:focus-visible .eq-stacked-bar-tip {
    top: calc(100% + var(--eq-space-1));
    left: 0;
    max-width: 100cqi;
  }

  @media (hover: hover) {
    .eq-stacked-bar-item:hover {
      z-index: 1;
    }

    .eq-stacked-bar-item:hover .eq-stacked-bar-label {
      color: var(--eq-ink);
    }

    .eq-stacked-bar-item:hover .eq-stacked-bar-tip {
      z-index: 1;
      width: max-content;
      max-width: calc(50cqi - var(--eq-space-3));
      height: auto;
      margin: 0;
      padding: var(--eq-space-1) var(--eq-space-2);
      overflow: visible;
      clip-path: none;
      white-space: normal;
      border: 1px solid var(--eq-line-strong);
      border-radius: var(--eq-radius-m);
      background: var(--eq-raised);
      box-shadow: var(--eq-shadow);
      -webkit-backdrop-filter: var(--eq-blur);
      backdrop-filter: var(--eq-blur);
    }

    .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-item[data-side="start"]:hover .eq-stacked-bar-tip {
      left: calc(50% + var(--eq-space-4) + 2px);
    }

    .eq-stacked-bar[data-orientation="vertical"] .eq-stacked-bar-item[data-side="end"]:hover .eq-stacked-bar-tip {
      right: calc(50% + var(--eq-space-4) + 2px);
    }

    .eq-stacked-bar[data-orientation="horizontal"] .eq-stacked-bar-item:hover .eq-stacked-bar-tip {
      top: calc(100% + var(--eq-space-1));
      left: 0;
      max-width: 100cqi;
    }
  }
}

EqUIp is in beta: free for non-commercial use, no warranty, and things can change. Terms

Nothing picked yet. Press A on a part, or use the plus on the board, and the install command builds here.

Loading the index.

Loading the index