Connection lost. Reconnecting… attempt 1 of 8
Paused. Your work is held on the server.
Could not reconnect.
This session has expired on the server.
An unhandled error has occurred.
Sedna.UI
v0.17.0 · main

Bars and meters

tier 2 — classes

The small charts a page of figures is made of: a list of bars to compare a handful of values, one bar split into parts that add up, a value against a scale with the thresholds marked, and a bar or a meter against its previous value. Each is markup and classes; the one number only the app knows is an inline custom property.

One colour family for every chart Every filled part paints currentColor, so which colour it is comes from one set of modifiers that a bar, a segment, a meter fill, a sparkline or a legend swatch all take. .series-1, .series-2, .series-3, .series-4, .series-5 and .series-6 are the categorical run — the brand first, then hues ordered so neighbours differ — for parts that are merely different from each other. .series-go, .series-warn, .series-danger, .series-info and .series-muted are the semantic families, for a part that means something. Never colour a category with a semantic family: a red slice says “danger” whether or not the data does. The brand is the default, so one series needs no modifier.

A list of bars

.bar-list is rows of label, bar and value, for comparing a few things down a column. The fill is --value, a percentage of the widest; the value is text as well as a bar, because the number is what the reader takes away and the bar is for the comparison. aria-current="true" on a row is the one the figure above is about, and --bar-list-label on the list widens the label column.

Open orders by region

EU-Central 1 240
EU-West 769
Nordics 384
Iberia 223
Other 74
<div class="card" style="max-width:520px">
    <div class="card-head"><h3>Open orders by region</h3></div>
    <div class="card-body">
        <div class="bar-list">
            <div class="bar-list-row" aria-current="true">
                <span class="bar-list-label">EU-Central</span>
                <span class="bar-list-track"><span class="bar-list-fill" style="--value: 100%"></span></span>
                <span class="bar-list-value">1 240</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">EU-West</span>
                <span class="bar-list-track"><span class="bar-list-fill" style="--value: 62%"></span></span>
                <span class="bar-list-value">769</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Nordics</span>
                <span class="bar-list-track"><span class="bar-list-fill" style="--value: 31%"></span></span>
                <span class="bar-list-value">384</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Iberia</span>
                <span class="bar-list-track"><span class="bar-list-fill" style="--value: 18%"></span></span>
                <span class="bar-list-value">223</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Other</span>
                <span class="bar-list-track"><span class="bar-list-fill" style="--value: 6%"></span></span>
                <span class="bar-list-value">74</span>
            </div>
        </div>
    </div>
</div>

Bars that mean something

The same list with the semantic families on the fills. Here the rows are outcomes, so the colour is a judgement the reader already makes — and .series-muted is for the part that is not yet anything.

Carrier performance, last 7 days

Delivered on time 91%
Delivered late 7%
Lost or damaged 2%
Not yet scanned 4%
<div class="card" style="max-width:520px">
    <div class="card-head"><h3>Carrier performance, last 7 days</h3></div>
    <div class="card-body">
        <div class="bar-list" style="--bar-list-label: 11rem">
            <div class="bar-list-row">
                <span class="bar-list-label">Delivered on time</span>
                <span class="bar-list-track"><span class="bar-list-fill series-go" style="--value: 91%"></span></span>
                <span class="bar-list-value">91%</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Delivered late</span>
                <span class="bar-list-track"><span class="bar-list-fill series-warn" style="--value: 7%"></span></span>
                <span class="bar-list-value">7%</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Lost or damaged</span>
                <span class="bar-list-track"><span class="bar-list-fill series-danger" style="--value: 2%"></span></span>
                <span class="bar-list-value">2%</span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Not yet scanned</span>
                <span class="bar-list-track"><span class="bar-list-fill series-muted" style="--value: 4%"></span></span>
                <span class="bar-list-value">4%</span>
            </div>
        </div>
    </div>
</div>

One bar in parts

.stack-bar is one bar whose segments add up: the states an order book is in, the share each carrier has. Each .stack-bar-segment is --value, and where they do not reach 100% the track shows through — the honest picture of a total that is not fully accounted for. The bar is one picture, so it takes role="img" and a label that says the numbers; the .stack-bar-legend under it is the same numbers for the eye, each key with a .stack-bar-swatch in the segment's colour. .stack-bar--lg is the taller track for a bar that is the point of a card, and .meter--lg the same for a meter.

Orders by state 128
Decided 79 Waiting 36 On hold 13
Volume by carrier 2 690 parcels
Northwind Express 41% Nordic Post 27% Iberia Courier 19% Others 13%
<div class="sedna-col sedna-gap-3" style="max-width:520px">
    <div class="card">
        <div class="card-body">
            <div class="stat">
                <span class="stat-label">Orders by state</span>
                <span class="stat-value">128</span>
            </div>
            <div class="stack-bar" style="margin-top: var(--space-5)" role="img" aria-label="128 orders: 79 decided, 36 waiting, 13 on hold">
                <span class="stack-bar-segment series-go" style="--value: 62%"></span>
                <span class="stack-bar-segment series-warn" style="--value: 28%"></span>
                <span class="stack-bar-segment series-muted" style="--value: 10%"></span>
            </div>
            <div class="stack-bar-legend">
                <span class="stack-bar-key"><span class="stack-bar-swatch series-go"></span> Decided 79</span>
                <span class="stack-bar-key"><span class="stack-bar-swatch series-warn"></span> Waiting 36</span>
                <span class="stack-bar-key"><span class="stack-bar-swatch series-muted"></span> On hold 13</span>
            </div>
        </div>
    </div>

    <div class="card">
        <div class="card-body">
            <div class="stat">
                <span class="stat-label">Volume by carrier</span>
                <span class="stat-value">2 690 <span class="stat-unit">parcels</span></span>
            </div>
            <div class="stack-bar stack-bar--lg" style="margin-top: var(--space-5)" role="img" aria-label="2 690 parcels: 41% Northwind Express, 27% Nordic Post, 19% Iberia Courier, 13% others">
                <span class="stack-bar-segment series-1" style="--value: 41%"></span>
                <span class="stack-bar-segment series-2" style="--value: 27%"></span>
                <span class="stack-bar-segment series-3" style="--value: 19%"></span>
                <span class="stack-bar-segment series-4" style="--value: 13%"></span>
            </div>
            <div class="stack-bar-legend">
                <span class="stack-bar-key"><span class="stack-bar-swatch series-1"></span> Northwind Express 41%</span>
                <span class="stack-bar-key"><span class="stack-bar-swatch series-2"></span> Nordic Post 27%</span>
                <span class="stack-bar-key"><span class="stack-bar-swatch series-3"></span> Iberia Courier 19%</span>
                <span class="stack-bar-key"><span class="stack-bar-swatch series-4"></span> Others 13%</span>
            </div>
        </div>
    </div>
</div>

A value against its thresholds

.meter differs from a progress bar in what the marks say: progress ends at 100% and is done, a meter has a line the reader does not want the fill to cross. Each .meter-mark is at --at, and .meter-mark-label names it; --labelled on the meter reserves the line under the track for those labels, and .meter-scale is the pair of end values under that. Where two marks sit close, .meter-mark--above moves one label over the track. The fill's colour is the app's judgement of the value — a series modifier — and the marks stay neutral.

Disk on src-db-14 71% 284 of 400 GB
0 GB400 GB
<div class="card" style="max-width:520px">
    <div class="card-body sedna-col sedna-gap-3">
        <div class="stat">
            <span class="stat-label">Disk on src-db-14</span>
            <span class="stat-value">71<span class="stat-unit">%</span></span>
            <span class="stat-target">284 of 400 GB</span>
        </div>
        <div class="meter meter--labelled" role="img" aria-label="71% used; alert at 80%, critical at 90%">
            <span class="meter-fill series-warn" style="--value: 71%"></span>
            <span class="meter-mark" style="--at: 80%"><span class="meter-mark-label">alert 80%</span></span>
            <span class="meter-mark meter-mark--above" style="--at: 90%"><span class="meter-mark-label">critical 90%</span></span>
        </div>
        <div class="meter-scale"><span>0 GB</span><span>400 GB</span></div>
    </div>
</div>

Meters in a table

Without labels, a meter is a cell: the mark is still the cap, the fill's family says how close each queue is, and the figures in the next column are the numbers. Give the column a width, or the meters shrink to the longest name.

Queues against their caps

QueueLoadCap
Orders 38 / 120
Exports 17 / 20
Notifications 496 / 500
<div class="card" style="max-width:560px">
    <div class="card-head"><h3>Queues against their caps</h3></div>
    <table class="table">
        <thead><tr><th>Queue</th><th style="width:45%">Load</th><th class="col-num">Cap</th></tr></thead>
        <tbody>
            <tr>
                <td>Orders</td>
                <td><div class="meter" role="img" aria-label="38 of 120"><span class="meter-fill" style="--value: 32%"></span><span class="meter-mark" style="--at: 85%"></span></div></td>
                <td class="col-num">38 / 120</td>
            </tr>
            <tr>
                <td>Exports</td>
                <td><div class="meter" role="img" aria-label="17 of 20"><span class="meter-fill series-warn" style="--value: 85%"></span><span class="meter-mark" style="--at: 85%"></span></div></td>
                <td class="col-num">17 / 20</td>
            </tr>
            <tr>
                <td>Notifications</td>
                <td><div class="meter" role="img" aria-label="496 of 500"><span class="meter-fill series-danger" style="--value: 99%"></span><span class="meter-mark" style="--at: 85%"></span></div></td>
                <td class="col-num">496 / 500</td>
            </tr>
        </tbody>
    </table>
</div>

This year against last

Use a comparison where the question is “better or worse than before” rather than “how much”: this year against last, this month against the one before. A .bar-previous goes first in the track, at its own --value, and the fill after it paints over it. Where the previous value was higher its hatch sticks out past the fill; where it was lower the fill covers the hatch and the line at its end is still there. .bar-list-previous puts the previous figure beside the current one, and a .stack-bar-legend with a .stack-bar-swatch--previous says which is which — without it a reader takes the hatch for a second series. Give each track role="img" and a label that states both values, with the period each belongs to.

Delivered on time, by region

EU-Central 72%(64%)
EU-West 58%(81%)
Nordics 89%(88%)
Iberia 41%(47%)
This year Last year
<div class="card" style="max-width:520px">
    <div class="card-head"><h3>Delivered on time, by region</h3></div>
    <div class="card-body">
        <div class="bar-list" style="--bar-list-label: 6rem">
            <div class="bar-list-row">
                <span class="bar-list-label">EU-Central</span>
                <span class="bar-list-track" role="img" aria-label="72% this year, 64% last year">
                    <span class="bar-previous" style="--value: 64%"></span>
                    <span class="bar-list-fill" style="--value: 72%"></span>
                </span>
                <span class="bar-list-value">72%<span class="bar-list-previous">(64%)</span></span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">EU-West</span>
                <span class="bar-list-track" role="img" aria-label="58% this year, 81% last year">
                    <span class="bar-previous" style="--value: 81%"></span>
                    <span class="bar-list-fill" style="--value: 58%"></span>
                </span>
                <span class="bar-list-value">58%<span class="bar-list-previous">(81%)</span></span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Nordics</span>
                <span class="bar-list-track" role="img" aria-label="89% this year, 88% last year">
                    <span class="bar-previous" style="--value: 88%"></span>
                    <span class="bar-list-fill" style="--value: 89%"></span>
                </span>
                <span class="bar-list-value">89%<span class="bar-list-previous">(88%)</span></span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Iberia</span>
                <span class="bar-list-track" role="img" aria-label="41% this year, 47% last year">
                    <span class="bar-previous" style="--value: 47%"></span>
                    <span class="bar-list-fill" style="--value: 41%"></span>
                </span>
                <span class="bar-list-value">41%<span class="bar-list-previous">(47%)</span></span>
            </div>
        </div>
        <div class="stack-bar-legend">
            <span class="stack-bar-key"><span class="stack-bar-swatch"></span> This year</span>
            <span class="stack-bar-key"><span class="stack-bar-swatch stack-bar-swatch--previous"></span> Last year</span>
        </div>
    </div>
</div>

Month against month, with the change

When the change matters more than the old figure, put a .stat-delta in the value column instead of .bar-list-previous. The arrow carries the direction and the modifier the judgement, exactly as under a stat, and a change too small to judge takes no modifier. The hatch is neutral whatever series the fill is; give .bar-previous the fill's .series-* only where both bars must share a hue.

Parcels by carrier, September

Northwind Express 1 10416%
Nordic Post 72611%
Iberia Courier 5113%
September August
<div class="card" style="max-width:520px">
    <div class="card-head"><h3>Parcels by carrier, September</h3></div>
    <div class="card-body">
        <div class="bar-list" style="--bar-list-label: 7.5rem">
            <div class="bar-list-row">
                <span class="bar-list-label">Northwind Express</span>
                <span class="bar-list-track" role="img" aria-label="1 104 parcels in September, 948 in August">
                    <span class="bar-previous" style="--value: 86%"></span>
                    <span class="bar-list-fill series-2" style="--value: 100%"></span>
                </span>
                <span class="bar-list-value">1 104<span class="stat-delta stat-delta--good"><i class="ri-arrow-up-line" aria-hidden="true"></i>16%</span></span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Nordic Post</span>
                <span class="bar-list-track" role="img" aria-label="726 parcels in September, 812 in August">
                    <span class="bar-previous" style="--value: 74%"></span>
                    <span class="bar-list-fill series-2" style="--value: 66%"></span>
                </span>
                <span class="bar-list-value">726<span class="stat-delta stat-delta--bad"><i class="ri-arrow-down-line" aria-hidden="true"></i>11%</span></span>
            </div>
            <div class="bar-list-row">
                <span class="bar-list-label">Iberia Courier</span>
                <span class="bar-list-track" role="img" aria-label="511 parcels in September, 498 in August">
                    <span class="bar-previous" style="--value: 45%"></span>
                    <span class="bar-list-fill series-2" style="--value: 46%"></span>
                </span>
                <span class="bar-list-value">511<span class="stat-delta"><i class="ri-arrow-up-line" aria-hidden="true"></i>3%</span></span>
            </div>
        </div>
        <div class="stack-bar-legend">
            <span class="stack-bar-key"><span class="stack-bar-swatch series-2"></span> September</span>
            <span class="stack-bar-key"><span class="stack-bar-swatch stack-bar-swatch--previous"></span> August</span>
        </div>
    </div>
</div>

A meter or a progress bar against before

.bar-previous works the same way as the first child of a .meter or a .progress: disk now against a week ago, a sprint against the last one on the same day. On a meter the previous value's line sits beside the threshold marks, so keep the legend. A .stack-bar takes no previous value: its parts are shares of one total, and two totals compare better as two stack bars, one above the other.

Disk on src-db-14 71% 77% a week ago
Now A week ago
Tickets closed this sprint 44 of 80 52 closed by the same day last sprint
<div class="sedna-col sedna-gap-3" style="max-width:520px">
    <div class="card">
        <div class="card-body sedna-col sedna-gap-3">
            <div class="stat">
                <span class="stat-label">Disk on src-db-14</span>
                <span class="stat-value">71<span class="stat-unit">%</span></span>
                <span class="stat-target">77% a week ago</span>
            </div>
            <div class="meter meter--labelled" role="img" aria-label="71% used now, 77% a week ago; alert at 80%">
                <span class="bar-previous" style="--value: 77%"></span>
                <span class="meter-fill series-warn" style="--value: 71%"></span>
                <span class="meter-mark" style="--at: 80%"><span class="meter-mark-label">alert 80%</span></span>
            </div>
            <div class="stack-bar-legend">
                <span class="stack-bar-key"><span class="stack-bar-swatch series-warn"></span> Now</span>
                <span class="stack-bar-key"><span class="stack-bar-swatch stack-bar-swatch--previous"></span> A week ago</span>
            </div>
        </div>
    </div>

    <div class="card">
        <div class="card-body sedna-col sedna-gap-3">
            <div class="stat">
                <span class="stat-label">Tickets closed this sprint</span>
                <span class="stat-value">44 <span class="stat-unit">of 80</span></span>
                <span class="stat-target">52 closed by the same day last sprint</span>
            </div>
            <div class="progress" role="img" aria-label="44 of 80 closed; 52 closed by the same day last sprint">
                <span class="bar-previous" style="--value: 65%"></span>
                <div class="progress-bar" style="width: 55%"></div>
            </div>
        </div>
    </div>
</div>