Skip to content

Limit Meter

Show a value against a limit, with the remaining amount and policy thresholds, such as spending.

import { AllowanceMarker, LimitMeter } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use an limit meter for a budget: what is left, large, with the spent and the limit as a quiet readout under it, over a ruler from zero to the limit. An index caret under the ruler points at the spend, and named lines mark the policies that act on it, so "how far until the card freezes" reads off the ruler.

import { LimitMeter } from '@youj/react'

<LimitMeter
  spent={1240}
  limit={2000}
  format={{ style: 'currency', currency: 'EUR' }}
  markers={[{ value: 1800, label: 'freeze', tone: 'warning' }]}
  label="Card limit"
/>

The ruler has 50 minor intervals with a major tick every 10 (ticks, majorEvery), and zero, the middle and the limit labeled under it. The remainder's decimals are set quieter than its whole part, whatever the locale's currency format. For a unit Intl has none for (GB, kcal), pass formatValue instead of format: a function that writes every amount and the scale.

Reference

Propsspent, limit, markers… (9)

Props

LimitMeter props
PropType
spentRequirednumber–
limitRequirednumber–
markersAllowanceMarker[]

Named lines on the ruler, e.g. the amount at which a card freezes.

–
formatIntl.NumberFormatOptions

Intl.NumberFormat options for the amounts, e.g. { style: 'currency', currency: 'EUR' }. Default: two decimals.

–
formatValue(value: number) => string

Writes every amount (and the scale) with your own function, for units Intl has none for ("12.5 TB"). Replaces format.

–
localestring

Default: the YoujProvider locale.

–
ticksnumber

Minor intervals on the ruler.

default 50

50
majorEverynumber

Every how many minor ticks a major one falls.

default 10

10
toneAllowanceTone
'accent''success''warning''danger''neutral'

The spent ticks' tone.

default 'success'

'success'
labelstring

Names the meter for assistive tech. Default: the visible "Remaining".

–
Other props pass through: extends MeterPrimitive.Root.Props.
StylingParts and data attributes

Styling

Parts: limit-meter, limit-meter-header, limit-meter-label, limit-meter-remaining, limit-meter-fraction, limit-meter-summary, limit-meter-stat, limit-meter-scale, limit-meter-flags, limit-meter-flag, limit-meter-ruler, limit-meter-tick (with data-major and data-zone: spent, runway or idle), limit-meter-marker, limit-meter-spent (the hairline at the spend), limit-meter-caret and limit-meter-axis. The root has data-state (within or over).

MotionReveal, each tick, new spend or limit · reduced motion

Motion

Motion tokens
MomentTokens
Revealwhen it scrolls into view the spend sweeps up from zero at a constant rate: the caret rides the front and the ticks light as it passes
duration.deliberate

560ms

560ms
Each tickfades to its zone’s tone
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
New spend or limitsweeps on from where the caret is; markers glide to their new place
duration.baseease.standard

220ms · cubic-bezier(0.2, 0, 0, 1)

220mscubic-bezier(0.2, 0, 0, 1)

Reduced motion

Drawn at its value; a new spend or limit is drawn in place.

Reduced motion

The ruler, the caret and the ticks are drawn at the value, with no sweep.

AccessibilityLabels and assistive technology

Accessibility

  • It's a meter (Base UI Meter) whose value is the spend and whose maximum is the limit. Name it with label; without one it's named by the visible "Remaining", which reads "Over limit" once the spend passes the limit.
  • Its value text says it all: "€1,240.00 spent of €2,000.00, €760.00 left, freeze at €1,800.00". Every word comes from labels (allowanceValueText, allowanceOverText, allowanceMarkerAt, …), translated in all 14 language packs.
  • The ruler is hidden from assistive tech. It runs from the inline start, so right to left in RTL.