Meter
A level against a scale, read at a glance: how full it is, and where a target or a limit sits on the same scale. Loudness against a target, storage against a quota, a budget against its limit.
tsx
import { Meter } from '@adecore/ui';tsx
import { Meter, useNow } from '@adecore/ui';
import { formatDecimal, formatPercent } from '@adecore/ui/format';
const FLOOR = -40;
const TOP = -4;
const TARGET = -14;
// A loudness that swells and dips, as a song under the playhead would.
function loudnessAt(seconds: number, speed: number): number {
return -20 + 7 * Math.sin(seconds * speed) + 3 * Math.sin(seconds * speed * 3.7);
}
export default function MeterDemo() {
const now = useNow(100);
const seconds = now / 1000;
const rows = [
{ letter: 'M', name: 'Momentary loudness', loudness: loudnessAt(seconds, 2.3) },
{ letter: 'S', name: 'Short-term loudness', loudness: loudnessAt(seconds, 0.6) }
];
return (
<div className="flex w-full max-w-xs flex-col gap-6">
<div role="group" aria-label={`Loudness against ${TARGET} LUFS`} className="flex flex-col gap-0.5">
{rows.map((row) => (
<div key={row.letter} className="flex items-center gap-1.5 text-xs">
<span aria-hidden className="w-2.5 text-text-faint">
{row.letter}
</span>
<Meter
value={row.loudness}
min={FLOOR}
max={TOP}
marks={[TARGET]}
label={row.name}
valueText={`${formatDecimal(row.loudness)} LUFS`}
className="flex-1"
/>
<span aria-hidden className="w-8 text-right text-text-muted tabular-nums">
{formatDecimal(row.loudness)}
</span>
</div>
))}
</div>
<div className="flex flex-col gap-1.5 text-xs">
<div className="flex justify-between text-text-muted">
<span>Storage</span>
<span className="tabular-nums">{formatPercent(62)}</span>
</div>
<Meter value={62} marks={[80]} label="Storage" valueText={`${formatPercent(62)} used`} />
</div>
</div>
);
}value is clamped between min and max. null draws an empty track, for a level not measured yet. marks draws a line across the track at each value, such as a target or a limit.
tsx
<Meter value={loudness} min={-40} max={-4} marks={[-14]} label="Momentary loudness" valueText={`${formatDecimal(loudness)} LUFS`} />It is a thin bar with no width of its own: className gives it one, or a flex row stretches it. It draws only the bar; you lay out the name and value. The fill has no transition, so fast updates follow without lag.
A screen reader hears a meter named by label, with valueText as the value ("-18.2 LUFS", "Measuring"), or else the number.
Props
| Prop | Type | Default | |
|---|---|---|---|
value | number | null | Required. null draws an empty track. | |
label | string | Required. The name a screen reader reads. | |
min | number | 0 | |
max | number | 100 | |
marks | readonly number[] | [] | Values drawn as lines across the track. |
valueText | string | The value in words for a screen reader. | |
className | string | Its width. | |
ref | Ref<HTMLDivElement> |
MeterProps is an exported type.