Hairline stat strip
A row of stat tiles joined by hairlines that are grid gap, not borders — the container paints the border color and the tiles paint the surface, so separators never double up or break when the row wraps — in a reporting form and in a second form where each tile is the filter for the list beneath it.
Reach for it when building
- 01summary strip at the top of a detail page
- 02dashboard KPI row
- 03account usage overview
- 04report header figures
- 05profile stats band
Tags
The preview below is printed in this site's two inks. The source panes carry the library's shared tokens, so the pattern keeps no palette of its own.
Reporting only — the figures are the whole job.
Same strip, working as the filter. Press a tile to narrow the list; press it again to clear.
- Bicycle drivetrain teardownDone
- Kiln firing, part threeDownloading
- Field recording — marsh at dawnQueued
- Lathe restoration, episode 12Done
- Sourdough hydration testsFailed
- Bookbinding: the long stitchQueued
Showing all 6 downloads.
<p class="hss-cap">Reporting only — the figures are the whole job.</p>
<div class="hss-strip four">
<div class="hss-tile"><span class="l">Documents</span><span class="v">1,482</span><span class="u">this period</span></div>
<div class="hss-tile"><span class="l">Median time</span><span class="v">3.2s</span><span class="u">last 24h</span></div>
<div class="hss-tile"><span class="l">Clean runs</span><span class="v">98.4%</span><span class="u">no retries</span></div>
<div class="hss-tile"><span class="l">Quality score</span><span class="v none" aria-label="No value">—</span><span class="u">not rated yet</span></div>
</div>
<p class="hss-cap">Same strip, working as the filter. Press a tile to narrow the list; press it again to clear.</p>
<div class="hss-strip five" id="hss-filter">
<button class="hss-tile" type="button" data-status="All" aria-pressed="false"><span class="l">All</span><span class="v">6</span><span class="u">downloads</span></button>
<button class="hss-tile" type="button" data-status="Queued" aria-pressed="false"><span class="l">Queued</span><span class="v">2</span><span class="u">downloads</span></button>
<button class="hss-tile" type="button" data-status="Downloading" aria-pressed="false"><span class="l">Downloading</span><span class="v">1</span><span class="u">download</span></button>
<button class="hss-tile" type="button" data-status="Done" aria-pressed="false"><span class="l">Done</span><span class="v">2</span><span class="u">downloads</span></button>
<button class="hss-tile" type="button" data-status="Failed" aria-pressed="false"><span class="l">Failed</span><span class="v">1</span><span class="u">download</span></button>
</div>
<ul class="hss-list" id="hss-list">
<li data-status="Done"><span>Bicycle drivetrain teardown</span><span>Done</span></li>
<li data-status="Downloading"><span>Kiln firing, part three</span><span>Downloading</span></li>
<li data-status="Queued"><span>Field recording — marsh at dawn</span><span>Queued</span></li>
<li data-status="Done"><span>Lathe restoration, episode 12</span><span>Done</span></li>
<li data-status="Failed"><span>Sourdough hydration tests</span><span>Failed</span></li>
<li data-status="Queued"><span>Bookbinding: the long stitch</span><span>Queued</span></li>
</ul>
<p class="hss-status" id="hss-status" role="status" aria-live="polite">Showing all 6 downloads.</p>Colors come from shared theme tokens — --surface, --ink, --border, --accent and friends — so this CSS carries no palette of its own. Use Runnable file to copy the tokens along with it.
.hss-strip {
display: grid;
gap: 1px;
background: var(--border);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
grid-template-columns: 1fr;
}
@media (min-width: 21rem) { .hss-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 42rem) {
.hss-strip.four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.hss-strip.five { grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); }
}
.hss-tile { background: var(--surface); padding: .9rem 1rem; min-width: 0; }
.hss-tile .l { font: 600 .8125rem/1.3 ui-monospace, monospace; text-transform: uppercase; letter-spacing: .08em; }
.hss-tile .v { font-size: 1.6rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.hss-tile .v.none { color: var(--dim); }
button.hss-tile[aria-pressed="true"] {
background: color-mix(in srgb, var(--accent) 14%, var(--surface));
}:root {
--ground: #eef0f3; --surface: #ffffff; --surface-2: #f5f7f9; --border: #d2d8e0;
--ink: #161b22; --dim: #56606e; --accent: #364f6a; --radius: 10px;
}const strip = document.getElementById('hss-filter');
const tiles = [...strip.querySelectorAll('button')];
const rows = [...document.querySelectorAll('#hss-list li')];
const status = document.getElementById('hss-status');
tiles.forEach((tile) => tile.addEventListener('click', () => {
const already = tile.getAttribute('aria-pressed') === 'true';
const target = already || tile.dataset.status === 'All' ? 'All' : tile.dataset.status;
tiles.forEach((other) => other.setAttribute('aria-pressed', String(other.dataset.status === target && target !== 'All')));
const shown = rows.filter((row) => (row.hidden = !(target === 'All' || row.dataset.status === target)) === false).length;
status.textContent = target === 'All'
? 'Showing all 6 downloads.'
: `Filtered to ${target}: ${shown} of 6. Press the lit tile again to clear.`;
}));Build a strip of statistic tiles that reads as one joined instrument panel rather than a row of floating cards.
The separators between tiles must not be borders. Make the container a CSS grid with `gap: 1px` and give the container itself the border color as its background; each tile then paints the surface color on top. The 1px of container showing through the gap is the hairline. This is the entire pattern: real borders double where two tiles meet and leave a stray edge when auto-fit wraps the row, and a gap physically cannot do either.
Pin the column counts instead of trusting auto-fit for the reporting form: one column by default, two from 21rem, four from 42rem. A strip that reflows to three-plus-one looks broken.
Tile anatomy: a mono uppercase label (0.8125rem), the figure (1.6rem, bold, tabular-nums), and a short unit line. Keep units with the number.
Two rules of honesty: render a missing value as a dimmed em dash, never a zero; and keep the unit beside the figure so a reader never has to guess what it counts.
The filter form: each tile is a button with aria-pressed, not a tab. Compute the counts from the unfiltered set so they never change as you filter. Pressing the lit tile again clears the filter, and a live status line says what is showing.
Full prompt continues with sections on pinning column counts, tile anatomy, the two rules of honesty, the filter form, and aria-pressed over tab roles.