A <figure class="bar-chart"> draws a
<table> of values as horizontal bars that grow
from zero. The first column of the table labels each row. Each
further column is a series named by its header cell.
It takes the same markup as a column chart. Use bars when the labels are long, when the rows are a ranking, or when there are more rows than fit across the page. The labels sit at the inline start of each row. The plot grows with the number of rows. A band and a tooltip follow the pointer, and the up and down arrows move them when the chart has focus.
<figure class="bar-chart">
<figcaption>Monthly revenue, first half</figcaption>
<table>
<thead>
<tr><th>Month</th><th>Revenue</th></tr>
</thead>
<tbody>
<tr><th>Jan</th><td>$4,400</td></tr>
<tr><th>Feb</th><td>$5,500</td></tr>
<tr><th>Mar</th><td>$4,100</td></tr>
<!-- One row per month -->
</tbody>
</table>
</figure>
Several series
Each value column after the first adds a bar to every row, and a
legend appears. Series take primary,
tertiary, secondary and
on-surface-variant in turn. Two or three series per row
stay readable. Add toggle to the figure to make each legend item a button that shows or hides its series, as on the line chart.
<figure class="bar-chart">
<figcaption>Subscriptions by plan</figcaption>
<table>
<thead>
<tr><th>Month</th><th>Basic</th><th>Premium</th></tr>
</thead>
<tbody>
<tr><th>Jan</th><td>5,500</td><td>4,900</td></tr>
<!-- One row per month -->
</tbody>
</table>
</figure>
Stacked
Add stacked to draw one bar per row, with each series
after the ones before it. The bar's length is the total. Only the
last segment rounds its end. Stack values that add up, and keep them
positive. An empty cell leaves the total unknown, so the chart
leaves out the segments after it.
<figure class="bar-chart stacked">
<figcaption>Subscriptions by plan, stacked</figcaption>
<table><!-- … --></table>
</figure>
Track and values
Add track to draw a full-width track behind each row
and round both ends of its bars. Add values to write
each cell's text from its bar's base, so a ranking reads without the
tooltip. Over the bar, the text takes the series' on-color. A value
longer than a short bar runs on past its end in the label color. Put the
number in data-value when the text is abbreviated.
<figure class="bar-chart track values" style="
--md-comp-bar-chart-row-height: 48px;
--md-comp-bar-chart-shape: 12px;
--md-comp-bar-chart-grid-color: transparent">
<figcaption>Visitors by source</figcaption>
<table>
<thead>
<tr><th>Source</th><th>Visitors</th></tr>
</thead>
<tbody>
<tr><th>Search</th><td data-value="900000">900K</td></tr>
<tr><th>Instagram</th><td data-value="650000">650K</td></tr>
<!-- One row per source -->
</tbody>
</table>
</figure>
Meter
One stacked row with a track and a
data-max is a meter. The segments are what is used and
the track is what is left. Add split to separate the
segments with a gap and round them at each joint. The legend names
the segments, and the tooltip lists every cell. In a stacked bar, values
keeps each segment's text inside it and cuts what does not fit.
- Spending limit
- $4,200
- of $10,000 this month
<article class="outlined">
<div class="p-4">
<dl class="stats my-0">
<div>
<dt>Spending limit</dt>
<dd>$4,200</dd>
<dd class="stat-change">of $10,000 this month</dd>
</div>
</dl>
<figure class="bar-chart stacked split track" data-max="10000" style="
--md-comp-bar-chart-bar-height: 100%;
--md-comp-bar-chart-shape: 8px;
--md-comp-bar-chart-grid-color: transparent">
<figcaption class="visually-hidden">Spending by category, April</figcaption>
<table>
<thead>
<tr><th>Month</th><th>Ads</th><th>Software</th><th>Payroll tools</th><th>Team events</th></tr>
</thead>
<tbody>
<tr><th>Apr</th><td>$1,450</td><td>$1,120</td><td>$890</td><td>$740</td></tr>
</tbody>
</table>
</figure>
</div>
</article>
Use sparkline for a bar beside a figure that already
explains it. It drops the label, grid, legend and tooltip.
Chart cards
Put a chart in a card with the figures it explains. Labels take up to 40% of the width and end in an ellipsis past it. The card adds no chart styles, so size a chart with its tokens.
- Total revenue
- $24,200
- +14.5% from last year
<article class="outlined">
<div class="p-4">
<dl class="stats my-0">…</dl>
<figure class="bar-chart values"
style="--md-comp-bar-chart-grid-color: transparent">
<figcaption class="visually-hidden">Revenue by country</figcaption>
<table><!-- … --></table>
</figure>
</div>
</article>
Values and scale
Cells read as in a column chart. A cell's number is its text without currency signs, percent signs or grouping commas. Text that is not a single number is a gap. In a grouped chart, a gap leaves an empty slot, so the other series stay in place.
The value axis always includes zero. It leaves 10% of the span to
spare past the longest bar, and before the shortest when there are
negative values. Negative bars grow toward the inline start and round that
end. Set data-min or data-max on the
figure to fix either end.
Add axis to label the value axis at round values. The
labels sit under the plot, with a grid line up from each. The chart
widens an end it chose to the next round value, so the labels start
and end on the plot's edges. An end set with data-min
or data-max stays where it is. The labels repeat any
currency or percent sign the cells are written with, and shorten
large numbers, such as $1.5K. They are hidden from
assistive technology, and the table still carries the values.
<figure class="bar-chart axis">
<figcaption>Net cash flow, first half</figcaption>
<table>
<thead><tr><th>Month</th><th>Net</th></tr></thead>
<tbody>
<tr><th>Jan</th><td>$1,200</td></tr>
<tr><th>Feb</th><td>−$400</td></tr>
<!-- One row per month -->
</tbody>
</table>
</figure>
Accessibility
The table is the chart's text alternative. Give it a header row and
a header cell per row, and name the chart with a
<figcaption>. The drawn bars, values, labels and
legend are hidden from assistive technology.
The plot is one Tab stop named by the caption. Up and down arrows move between rows. Home and End jump to the ends, and Escape hides the tooltip. On a touch screen, tap a row to show it. In a right-to-left page, the labels sit on the right and the bars grow leftwards. The rows keep their order. The tooltip is a polite live region, so a screen reader hears each row's values as it moves. A sparkline is not focusable. In forced colors the bars keep their series colors so the legend still keys them.
JavaScript
AutoInit() starts every .bar-chart. To
start one yourself, call BarChart.init. After you change
its table, call update() to redraw it in place. Or put
data-watch on the figure, and it redraws itself. The
bars move from their old values to the new ones, and a new bar grows
from zero. With reduced motion, they appear at once. The bar chart
takes the column chart's options and methods.
const chart = Expressive.BarChart.init(document.querySelector('.bar-chart'), {
max: 10000
});
chart.show(2); // highlight the third row; -1 hides the tooltip
chart.update(); // redraw from the table; focus and the highlighted row stay
chart.destroy(); // remove the drawing and show the table again
| Option | Default | Description |
|---|---|---|
min | null | Lowest value. data-min overrides it. |
max | null | Highest value. data-max overrides it. |
Tokens
Override these on the .bar-chart. The plot is as tall
as its rows, so the shared --md-comp-bar-chart-height
has no effect.
| Token | Default |
|---|---|
--md-comp-bar-chart-row-height | 40px, 24px for a sparkline |
--md-comp-bar-chart-bar-height | 60% of each row's height |
--md-comp-bar-chart-shape | 4px |
--md-comp-bar-chart-track-color | --md-sys-color-surface-container-highest |
--md-comp-bar-chart-grid-color | --md-sys-color-outline-variant |
--md-comp-bar-chart-color-1 | --md-sys-color-primary |
--md-comp-bar-chart-color-2 | --md-sys-color-tertiary |
--md-comp-bar-chart-color-3 | --md-sys-color-secondary |
--md-comp-bar-chart-color-4 | --md-sys-color-on-surface-variant |
--md-comp-bar-chart-on-color-1 … -4 | on-primary, on-tertiary, on-secondary, surface; text from values |
For a selective Sass build, include "bar-chart" in $components.