# Meter

A value inside a known range, read off an LED strip. The strip is a native meter element, so low, high and optimum are the browser’s own: the whole lit length takes the colour of where the value stands (green in the good region, amber next to it, red beyond), not the colour of the segment it has reached. The marks under the strip print where the regions begin, and cut lines across it show the same two places. Words say the state too.

Kit part · Free · https://tactileui.dev/parts/meter

- Element: `<meter class="tui-meter__strip">`
- Needs: `kit.css` only, no script ([how to install the kit](https://tactileui.dev/docs/installation#the-kit))
- Categories: Progress
- Finishes: Aluminium, Graphite, Oak, Walnut, Porcelain, Black, Daylight, Night, Paper, Phosphor, E-paper, AMOLED
- Volumes: Tactile, Quiet

## Variants

### A good end that is low · storage

```html
<div style="width:min(100%,400px)"><div class="tui-meter" style="--lo:0.5;--hi:0.85" data-state="good" data-good="Plenty free" data-fair="Getting full" data-poor="Nearly full">
  <div class="tui-meter__head"><label class="tui-label" for="mt1">Storage used</label> <span class="tui-meter__value">31 GB</span> <span class="tui-meter__state"><span class="tui-lamp" data-lamp="green" data-on aria-hidden="true"></span><span class="tui-meter__words">Plenty free</span></span></div>
  <div class="tui-meter__strip"><meter id="mt1" min="0" max="100" low="50" high="85" optimum="20" value="31">31 GB</meter></div><div class="tui-meter__marks" aria-hidden="true"><span class="tui-meter__mark" style="--at:0"><span>0</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.5"><span>50</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.85"><span>85</span></span><span class="tui-meter__mark" style="--at:1"><span>100</span></span></div>
</div></div>
```

### A good end that is high · a score

```html
<div style="width:min(100%,400px)"><div class="tui-meter" style="--lo:0.4;--hi:0.75" data-state="fair" data-good="Healthy" data-fair="Fair" data-poor="Poor">
  <div class="tui-meter__head"><label class="tui-label" for="mt2">Health score</label> <span class="tui-meter__value">58 points</span> <span class="tui-meter__state"><span class="tui-lamp" data-lamp="amber" data-on aria-hidden="true"></span><span class="tui-meter__words">Fair</span></span></div>
  <div class="tui-meter__strip"><meter id="mt2" min="0" max="100" low="40" high="75" optimum="100" value="58">58 points</meter></div><div class="tui-meter__marks" aria-hidden="true"><span class="tui-meter__mark" style="--at:0"><span>0</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.4"><span>40</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.75"><span>75</span></span><span class="tui-meter__mark" style="--at:1"><span>100</span></span></div>
</div></div>
```

### A good end in the middle · temperature

```html
<div style="width:min(100%,400px)"><div class="tui-meter" style="--lo:0.32;--hi:0.56" data-state="fair" data-good="In range" data-fair="Warm" data-poor="Far too warm">
  <div class="tui-meter__head"><label class="tui-label" for="mt3">Cabinet temperature</label> <span class="tui-meter__value">26 °C</span> <span class="tui-meter__state"><span class="tui-lamp" data-lamp="amber" data-on aria-hidden="true"></span><span class="tui-meter__words">Warm</span></span></div>
  <div class="tui-meter__strip"><meter id="mt3" min="10" max="35" low="18" high="24" optimum="21" value="26">26 °C</meter></div><div class="tui-meter__marks" aria-hidden="true"><span class="tui-meter__mark" style="--at:0"><span>10</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.32"><span>18</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.56"><span>24</span></span><span class="tui-meter__mark" style="--at:1"><span>35</span></span></div>
</div></div>
```

### No marks · --bare, with --lg

```html
<div style="width:min(100%,400px)"><div class="tui-meter tui-meter--lg tui-meter--bare" style="--lo:0.5;--hi:0.85" data-state="poor" data-good="Plenty free" data-fair="Getting full" data-poor="Nearly full">
  <div class="tui-meter__head"><label class="tui-label" for="mt4">Storage used</label> <span class="tui-meter__value">91 GB</span> <span class="tui-meter__state"><span class="tui-lamp" data-lamp="red" data-on aria-hidden="true"></span><span class="tui-meter__words">Nearly full</span></span></div>
  <div class="tui-meter__strip"><meter id="mt4" min="0" max="100" low="50" high="85" optimum="20" value="91">91 GB</meter></div>
</div></div>
```

### No thresholds · all optimum

```html
<div style="width:min(100%,400px)"><div class="tui-meter tui-meter--bare" style="--lo:0;--hi:1" data-state="good">
  <div class="tui-meter__head"><label class="tui-label" for="mt5">Profile complete</label> <span class="tui-meter__value">64 %</span></div>
  <div class="tui-meter__strip"><meter id="mt5" min="0" max="100" value="64">64 %</meter></div>
</div></div>
```

### Fewer segments · --n

```html
<div style="width:min(100%,400px)"><div class="tui-meter tui-meter--bare" style="--n:12;--lo:0.5;--hi:0.85" data-state="fair" data-good="Plenty free" data-fair="Getting full" data-poor="Nearly full">
  <div class="tui-meter__head"><label class="tui-label" for="mt6">Storage used</label> <span class="tui-meter__value">60 GB</span> <span class="tui-meter__state"><span class="tui-lamp" data-lamp="amber" data-on aria-hidden="true"></span><span class="tui-meter__words">Getting full</span></span></div>
  <div class="tui-meter__strip"><meter id="mt6" min="0" max="100" low="50" high="85" optimum="20" value="60">60 GB</meter></div>
</div></div>
```

## Every state

- Good
- Fair
- Poor

Hover, pressed and focus are forced with `.is-hover`, `.is-down` and `.is-focus`; checked and disabled are real.

## API

| Name | Kind | Values | What it does |
| - | - | - | - |
| div.tui-meter | element | --lo and --hi | The meter and its label, value and state. Set --lo and --hi (0 to 1) to where the meter’s low and high fall, so the cut lines and marks agree with them. |
| .tui-meter__strip > meter | element | min max low high optimum value | The native meter, drawn as the strip. It gives the screen reader its value and range and the browser the colour of the lit length. |
| .tui-meter__head | element | label, value, state | A real label for the meter, the figure and the state in words, with a lamp that agrees (green, amber or red). |
| .tui-meter__marks > .tui-meter__mark | element | --at: 0 to 1 | A printed tick under the strip and its figure, at that fraction of the range. Add --cut for the two thresholds. The first and last lean away from the edge. |
| --n | CSS property | 24 | The number of segments. |
| --lg · --bare | modifier | tui-meter--lg, --bare | A taller strip; or the strip without its cut lines. |
| meterState(value, range) · meterRegion() · meterFraction() | function | pure | The browser’s rule in code: "good", "fair" or "poor", which third of the range, and where in 0 to 1. |
| setMeter(root, value) | function | needs kit.mjs | Sets the native value, the lamp, the words from data-good, data-fair and data-poor, and fires tui-meter-change. |

## Markup

```html
<div class="tui-meter" style="--lo:.5;--hi:.85"
     data-good="Plenty free" data-fair="Getting full" data-poor="Nearly full">
  <div class="tui-meter__head">
    <label class="tui-label" for="disk">Storage used</label>
    <span class="tui-meter__value">72 GB</span>
    <span class="tui-meter__state">
      <span class="tui-lamp" data-lamp="amber" data-on aria-hidden="true"></span>
      <span class="tui-meter__words">Getting full</span>
    </span>
  </div>
  <div class="tui-meter__strip">
    <meter id="disk" min="0" max="100" low="50" high="85" optimum="20" value="72">72 GB</meter>
  </div>
  <div class="tui-meter__marks" aria-hidden="true">
    <span class="tui-meter__mark" style="--at:0"><span>0</span></span>
    <span class="tui-meter__mark tui-meter__mark--cut" style="--at:.5"><span>50</span></span>
    <span class="tui-meter__mark tui-meter__mark--cut" style="--at:.85"><span>85</span></span>
    <span class="tui-meter__mark" style="--at:1"><span>100</span></span>
  </div>
</div>
```

```js
import { setMeter, meterState } from '/kit/kit.mjs';

// Sets the native value, the lamp, the state's words and fires tui-meter-change.
setMeter(document.querySelector('.tui-meter'), 91);

meterState(91, { min: 0, max: 100, low: 50, high: 85, optimum: 20 });   // 'poor'
meterState(72, { min: 0, max: 100, low: 50, high: 85, optimum: 20 });   // 'fair'
```

The demo on the page:

```html
<div class="tui-panel" style="width:min(100%,460px);display:grid;gap:16px;text-align:left"><div class="tui-panel__head" style="margin-bottom:0"><span class="tui-label">Node 4 · Lode</span></div><div class="tui-meter" style="--lo:0.5;--hi:0.85" data-state="fair" data-good="Plenty free" data-fair="Getting full" data-poor="Nearly full" data-mt>
  <div class="tui-meter__head"><label class="tui-label" for="mt-demo">Storage used</label> <span class="tui-meter__value">72 of 100 GB</span> <span class="tui-meter__state"><span class="tui-lamp" data-lamp="amber" data-on aria-hidden="true"></span><span class="tui-meter__words">Getting full</span></span></div>
  <div class="tui-meter__strip"><meter id="mt-demo" min="0" max="100" low="50" high="85" optimum="20" value="72">72 GB</meter></div><div class="tui-meter__marks" aria-hidden="true"><span class="tui-meter__mark" style="--at:0"><span>0</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.5"><span>50</span></span><span class="tui-meter__mark tui-meter__mark--cut" style="--at:0.85"><span>85</span></span><span class="tui-meter__mark" style="--at:1"><span>100</span></span></div>
</div>
  <input class="tui-fader" type="range" min="0" max="100" value="72" aria-label="Storage used, in gigabytes" data-mt-drive>
  <output class="tui-muted" style="font-size:var(--tui-t-small)" data-mt-out aria-live="polite">Getting full: 72 of 100 GB used</output></div>
```

## Usage notes

Move the fader: the lit length grows, and where it crosses the cut lines it changes colour as a whole and the words beside it change too. The cut lines are the low and the high, printed under the strip. Below the demo the same strip is shown with its good end at the top, and with it in the middle.

## Accessibility

- The strip is a native `<meter>` with a real `<label>`, so a screen reader says “Storage used, meter, 72 of 100”, with the range and the value, and no ARIA is needed.
- The state is said in words next to the strip (“Getting full”) with a lamp that agrees; the lit length changing colour is never the only sign. The marks and the cut lines are decoration for the eye and are hidden, since the thresholds are in the meter itself.
- The words are the secondary ink, at least 4.5:1 on the plate, and the strip is a dark window whose edge is seen at 3:1 in every finish.
- It takes no focus. The lit length eases for 120ms when it changes; under reduced motion it does not, and every figure is the same.
- On a phone the strip and the marks scale to the width and the first and last marks stay on the plate, so there is no sideways scroll at 390px.

## How it’s built

It is the ladder’s dark glass with the opposite idea in it. The ladder paints its segments by position, green then amber then red along its length, so it shows how far up a scale something is. The meter paints the whole lit length one colour, chosen by the native meter from low, high and optimum, so it shows whether the value is good: the same 40 on a strip whose good end is high is red and on one whose good end is low is green. The cut lines and printed marks are drawn from two custom properties, and the segment gaps are laid over the browser’s own bar.

## Rules

Show where a value stands between a low and a high that matter: storage used, a score, a cabinet’s temperature, with the thresholds printed under the strip.

The full rules are in `meter.rules.md` in the brain, which ships with the Kit.

## Related parts

- [Ladder](https://tactileui.dev/parts/ladder): An LED ladder for levels and load: green, then amber, then red, the way a recording level has always been read.
- [Progress](https://tactileui.dev/parts/progress): Progress through a task: ink filling a groove, never a coloured bar.
- [Battery](https://tactileui.dev/parts/battery): A cell outline with a terminal at one end, filled with lamp segments set into a recess, lit from the empty end. The lit segments are one lamp colour for the whole cell: green, amber below two fifths, red below a fifth. While it charges, the top lit segment breathes. The level is said in words too, so neither the colour nor the breathing is the only sign.
- [Lamp](https://tactileui.dev/parts/lamp): The only colour in the kit: a lamp that is on. Green is on, amber is waiting, red is recording or failing, blue is linked, white is standing by. Always next to words.
