Skip to content

Meter

A quantity within a known range, such as wallet usage, storage or a limit, with a label, a readout and a slim track.

Preview

Consultations₹7,400 usedof ₹18,000

Installation

pnpm add @syntara/react @syntara/tokens
import { Meter } from '@syntara/react';

Usage

import { Meter } from '@syntara/react';

export function WalletUsage() {
  return <Meter label="Consultations" value={7400} maxValue={18000} valueLabel="₹7,400 used" caption="of ₹18,000" />;
}

Examples

Card variant

variant="card": the usage row inside a card, in an inset panel.

In-clinic consultation

GP, specialist or a second opinion

Cashless
₹2,600 usedfrom ₹18K wallet

Tones

brand (default), accent, warning and neutral fills.

Medicines₹3,200 usedof ₹18,000
Diagnostics₹9,100 usedof ₹18,000
Dental₹4,600 usedof ₹5,000
VisionNot used yet

Formats

Percent by default, currency via formatOptions, and an aria-label-only meter.

Storage64%
Monthly budget£1,840of £2,500
7 of 10 seats

Accessibility

No keyboard interaction of its own.

  • Rendered by React Aria as role="meter progressbar" with aria-valuenow/min/max and aria-valuetext; it is read-only and takes no focus.
  • The caption is linked with aria-describedby (merged with any you pass), so "of ₹18,000" is read after the value.
  • Fill contrast (WCAG 1.4.11): fills use text roles, not action.primary.bg. action.primary.bg fell to 2.64:1 on surface.sunken in Care dark and below 3:1 in 709 of 2,000 fuzz schemes; text.brand stays ≥ 4.46:1 on sunken across the same fuzz and is guaranteed 4.5:1 on surface.default (the card variant's track).
  • The fill slides in from the start edge with easing-out only when reduced motion is off; otherwise it is simply drawn at its width.
  • Value text takes the locale's direction (formatted) or its own (authored strings), so readouts don't reorder in RTL.

Guidelines

Do

  • Use Meter for amounts against a limit (money used, seats taken, storage).
  • Say what the number means in valueLabel ("₹7,400 used"), and give the limit in caption.
  • Use variant="card" for the usage row at the bottom of a benefit or plan card.

Don’t

  • Don't use Meter for task progress; use ProgressBar.
  • Don't rely on tone alone to signal "nearly used up"; say it in the caption.
  • Don't put more than a few meters in one card: summarise instead.

API reference

Meter

label
ReactNode

Visible label. Without one, pass aria-label or aria-labelledby (required by the types).

value
number

Current value, clamped to minValue–maxValue.

Default 0

minValue
number

Start of the range.

Default 0

maxValue
number

End of the range.

Default 100

valueLabel
string

The value as shown and announced (aria-valuetext), e.g. "₹7,400 used".

formatOptions
Intl.NumberFormatOptions

How the value is formatted when there's no valueLabel, in the React Aria locale.

Default { style: 'percent' }

showValue
boolean

Shows the value in the label row.

Default true

caption
ReactNode

Quiet context after the value: the limit or the pool ("of ₹18,000", "from ₹18K wallet"). Announced as the meter's description.

tone
  • branddefault
  • accent
  • neutral
  • info
  • success
  • warning
  • danger

Fill colour: text.brand, accent.text, text.subtle or the feedback fg role. Every tone reaches 3:1 against the track.

variant
  • defaultdefault
  • card

card sets the meter in an inset surface.sunken panel: the value leads, the caption answers from the far end, the label (if any) sits above in text.subtle.

Tokens

The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.

Colour8
text.brandaccent.texttext.subtlefeedback.*.fgsurface.sunkensurface.defaultborder.subtletext.default
Type1
font-size.xs–md
Space and size2
card-insetspace.1–4
Shape3
radius.pillradius.containerradius.badge
Depth1
hairline
Motion3
motion.duration-slowmotion.duration-fastmotion.easing-out