Navigation

v0.0.4
Data display

Stat

One figure, what it measures and how it moved.

On this page

A stat is one figure and what it measures: a quiet label, the value in large tabular figures, and an optional change beside it. It has no surface of its own. Put it in a card, or set several in a row. A figure that is a cost is a price.

Stat

<div class="tray grid grid-cols(3) gap(4)">  <div class="card card-flat">    <div class="stat">      <p class="stat-label">Requests</p>      <div class="stat-row">        <p class="stat-value">1.28M</p>        <p class="stat-delta stat-delta-up">12.4%</p>      </div>    </div>  </div>  <div class="card card-flat">    <div class="stat">      <p class="stat-label">Error rate</p>      <div class="stat-row">        <p class="stat-value">0.02%</p>        <p class="stat-delta stat-delta-down">0.4%</p>      </div>    </div>  </div>  <div class="card card-flat">    <div class="stat">      <p class="stat-label">Median response</p>      <div class="stat-row">        <p class="stat-value">84ms</p>        <p class="stat-delta">No change</p>      </div>    </div>  </div></div>

#The change

stat-delta sits on the value's baseline. stat-delta-up and stat-delta-down add an arrow and a status ink; without either it is a neutral note.

The modifiers describe the direction, and the color follows the direction: up is the success ink, down the danger ink. When a fall is good news, as with an error rate or a cost, say so in words, or leave the delta neutral. The arrow and the number carry the meaning; the hue only agrees with them.

#With a description

stat-description adds a line under the figure: the period, the comparison, or the target.

With a description

<div class="card max-w(320) mx-auto">  <div class="stat">    <p class="stat-label">Build minutes</p>    <div class="stat-row">      <p class="stat-value">3,412</p>      <p class="stat-delta stat-delta-up">8%</p>    </div>    <p class="stat-description">Of 6,000 included this month, compared with October.</p>  </div>  <meter class="meter" min="0" max="6000" low="4500" high="5700" optimum="0" value="3412" aria-label="Build minutes used">3,412 of 6,000</meter></div>

#Accessibility

  • The arrow is drawn by the stylesheet and is not announced. Write the direction into the text a screen reader gets, for example with a visually hidden "up" before the number.
  • Figures use tabular numerals, so a value that updates does not shift the text around it.
  • Several stats that describe one thing read well as a <dl>, with stat-label on the <dt> and the row inside the <dd>.

#Classes

ClassDescription
statThe group
stat-labelWhat is measured
stat-rowThe value and its change, on one baseline
stat-valueThe figure, in large tabular numerals
stat-deltaHow the figure moved; a neutral note without a direction
stat-delta-upAn arrow that points up and the success ink. With stat-delta
stat-delta-downAn arrow that points down and the danger ink. With stat-delta
stat-descriptionA line under the figure: the period, the comparison or the target

#Source

@master/ui/components/stat.css
/* * Stat: one figure and what it measures. A quiet label, the value in large tabular figures, and an optional * change beside it. A change carries a direction as an arrow and a status ink; the number says the same thing. * It has no surface of its own: put it in a card, or set several in a row. */@layer components {  .stat {    display: grid;    gap: .375rem;    min-width: 0;    margin: 0;  }  .stat-label {    margin: 0;    color: var(--color-text-muted);    font-size: .8125rem;    line-height: 1.4;  }  /* The figure and its change share a baseline. */  .stat-row {    display: flex;    flex-wrap: wrap;    align-items: baseline;    gap: .25rem .625rem;  }  .stat-value {    margin: 0;    color: var(--color-text-strong);    font: 400 1.75rem/1.15 var(--font-family-sans);    font-feature-settings: inherit;    font-variant-numeric: tabular-nums;    letter-spacing: -.02em;  }  /* How the figure moved. Neutral by default; up and down take an arrow and a status ink. */  .stat-delta {    display: inline-flex;    align-items: center;    gap: .125rem;    margin: 0;    color: var(--color-text-muted);    font-size: .8125rem;    font-variant-numeric: tabular-nums;    line-height: 1.4;    white-space: nowrap;    &:is(.stat-delta-up, .stat-delta-down)::before {      content: '';      flex: none;      width: .875rem;      height: .875rem;      background: currentColor;      mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 12.5v-9M4.5 7 8 3.5 11.5 7'/%3E%3C/svg%3E") center / contain no-repeat;    }    &.stat-delta-up {      color: var(--color-success);    }    &.stat-delta-down {      color: var(--color-danger);      &::before {        rotate: 180deg;      }    }    @media (forced-colors: active) {      &::before {        background: CanvasText;      }    }  }  .stat-description {    margin: 0;    color: var(--color-text-muted);    font-size: .75rem;    line-height: 1.5;    text-wrap: pretty;  }}