Value Readout

value-readoutViewers

The REDUCTION / -14.0 dB element every meter-bearing face grows, made once. Three things it insists on. The value is monospace with tabular figures, because a number that reflows as its digits change is unreadable while it moves, and a live readout moves constantly. The unit is a separate muted element beside the value rather than part of it, so the eye reads the magnitude first and a face can drop the unit without the number's typography shifting. And a missing value prints an em dash, never a zero — a meter with no source showing 0.0 dB claims a measurement it never received, which is the same "absent is not zero" rule the hosted face feeds follow. The negative case is pinned just as hard: a real zero prints as zero, because confusing a measured 0.0 with no reading at all would be the same bug wearing the other hat. The note line underneath is where the qualifier goes — "predicted", "reference pattern", "no tap from this host" — styled as secondary text so it never competes with the value, and an accent recolours the value alone, never a placeholder, so an em dash is never lit up like a live reading.

Reduction-14.0dBMeasured from the output tap
Budget-18.0dBHard ceiling
Tempo128BPMHost
GrantsNot reported by this host

Untick the tap and the first readout becomes an em dash with a note saying why — not 0.0 dB, which would be a measurement nobody made. A real zero still prints as zero; that negative case is pinned in the test, because confusing a measured 0.0 with "no reading" is the same bug wearing the other hat. Push the reduction past the budget and the value alone takes the warning accent, while the placeholder readout on the right never lights up at all. Figures are tabular, so the number does not reflow as its digits change.

Install

Copies the source into your project. Anything it depends on comes with it.

$ npx shadcn add @syntho-ui/value-readout

Pulls in

control-theme

First time? Add the registry to your components.json once:

components.json
{
  "registries": {
    "@syntho-ui": "https://engine.syntho.app/r/{name}.json"
  }
}

Usage

Controlled or uncontrolled, whichever suits the surrounding state.

example.tsx
import { ValueReadout } from "@/components/ui/value-readout"

// A live value, coloured by whether it is past the budget.
<ValueReadout
  label="Reduction"
  value={reduction.toFixed(1)}
  unit="dB"
  accent={reduction > budget ? "var(--uikit-accent-2)" : undefined}
  size="lg"
/>

// No source: an em dash and a note, never a fabricated 0.0.
<ValueReadout label="Reduction" value={null} unit="dB" note="No tap from this host" />

Props

PropTypeDefaultDescription
labelReactNodeCaption above the value. Short, uppercase by convention.
valueReactNodeThe value. A string prints verbatim (the host owns the rounding policy, so the readout imposes none); null, undefined, a non-finite number or an empty string print an em dash instead of a fabricated zero. A real 0 still prints as 0.
unitReactNodeUnit beside the value, smaller and muted so the magnitude reads first.
noteReactNodeSecondary line under the value — the qualifier that keeps the number honest, not more precision.
accentstringRecolour the value and unit — a budget exceeded, a warning state. Never applied to a placeholder.
size"sm" | "md" | "lg""md"Type scale. A table of three deliberate sizes rather than a continuum, so the value/unit ratio stays right at each.
align"start" | "center" | "end""start"Alignment of the whole block.

Interaction

  • Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
  • Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
  • Double-click resets to defaultValue.
  • Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
  • Proper slider and switch roles with live aria-valuetext, so a screen reader announces the formatted value rather than the raw number.
  • The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.