X Data

Star on GitHubFeedback
X DataNative HTMLot-meter

Meter

A bounded reading: your figure in large italic above a dimension line, one accent index locating it between its limits. Space remains space; nothing fills it in.

Report an issue with Meter

Example

28 GB available for the next project

At the minimum
At the maximum
A signed range
Right to left
Localized figures
A decimal reading

Install

Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base along.

npx shadcn@latest add https://thedirectors.agency/ui/r/meter.json

Usage

This example also uses Select.

npx shadcn@latest add https://thedirectors.agency/ui/r/select.json
meter-example.tsx
"use client"import * as React from "react"import { Meter } from "@/components/ui/meter"import { Select } from "@/components/ui/select"const projects = { "Film archive": 72, "Identity archive": 38, "Empty archive": 0, "Full archive": 100 }export default function Example() {const [project, setProject] = React.useState<keyof typeof projects>("Film archive")return (<div className="grid w-full max-w-xl gap-12"><Select label="Read the storage in" value={project} onChange={(e) => setProject(e.target.value as keyof typeof projects)}>{Object.keys(projects).map((name) => <option key={name}>{name}</option>)}</Select><Meter label="Storage used" value={projects[project]} max={100} unit=" GB" note={`${100 - projects[project]} GB available for the next project`} /></div>)}

Contract

  • Underneath: native <meter>, named by a native <label>. A known reading within limits, such as storage used or a budget balance; use progress for completion and slider for input.
  • Anatomy: .ot-meter holding .ot-meter-label, .ot-meter-scale (the visual reading, rule, index and two limits, all aria-hidden), a visually hidden native meter, and optional .ot-meter-note. Every part carries data-slot.
  • Creative move: Paul Rand's dimension lines. A large italic figure stands above a hairline between two end ticks; one accent index marks the exact reading. The empty measure stays empty. The space on either side of the figure shares the remaining width in proportion to the reading, keeping it inside both limits without measuring in script. Longer readings step down from ff toward mf to fit their measure, using the formatted length and container width; exceptionally long text still wraps in flow above the line rather than covering it. Labels and notes wrap too. Units and limits are roman; the reading is yours, in italic.
  • value is clamped to finite min and max, shared by the visible reading and native meter. Negative ranges work; non-finite values, an overflowing span and max not greater than min throw a RangeError. format sets all three figures and unit follows them as supplied. low, high and optimum retain the native semantics without introducing another colour.
  • The formatted reading names the value through aria-valuetext; callers can override it. The note joins any supplied aria-describedby. id, ref and other native meter props reach the meter; className, style, hidden, dir and lang apply to the root. It is a reading, with no tab stop or keyboard interaction.
  • Motion: legato. When the reading changes, one eased number drives the space around the figure and the index at moderato, so they glide together and an interrupted update continues from the current position; there is no entrance or autonomous loop. Reduced motion changes directly. Flex and logical positioning mirror the scale in right to left, including a locally overridden direction. Readings and limits use left-to-right bdi, so even a signed number without a lettered unit keeps its sign before the number; localized text retains its own bidi marks. Forced colours keeps the index in Highlight.

Props

Props of Meter
PropTypeDefaultWhat it does
labelReactNodeWhat is measured. A native label names the meter.
valuenumberThe reading, clamped to the range in both the display and the native meter. Must be finite. Use Progress for work being completed, and Slider for a value the reader can set.
min / maxnumber0 / 100Finite limits with max greater than min. Negative ranges work. Invalid ranges throw a RangeError rather than displaying a misleading scale.
unitstring""Written as supplied after every figure: " GB" with its space, "%" without. The reading is italic; its unit and the scale limits are roman.
format(value: number) => stringen-GB, up to two decimalsFormats the reading and both limits, such as a localized number or currency. Long figures scale down to the mf step, then wrap if needed. Choose the precision and locale explicitly when they matter.
noteReactNodeContext beneath the scale, also included in the native meter's accessible description.
Native meter propsmeter propsid, ref, low, high, optimum and aria attributes reach the native meter. aria-valuetext can supply a more descriptive reading; aria-describedby is joined with the note. className, style, hidden, dir and lang apply to the outer div.

Craft

Where its move comes from

Where its move comes from
ComponentReferenceMove
MeterPaul Rand dimension linesAn italic reading above an empty measure, one index between its limits

How it moves

How it moves
ComponentArticulationWhat moves
MeterLegatoA changed figure and its index glide to their new places, then rest