Skip to content

Refill Meter

Show capacity that drains with use and refills over time, such as a rate limit’s token bucket.

import { RefillMeter } 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 a refill meter where a client, a key or an endpoint spends from a token bucket: how much it can still send right now, and how fast that room comes back. Each cell is a token (or a share of a large bucket), lit while it's in the bucket. Requests drain cells from the edge; between the updates you give it, the bucket refills on its own at refillRate, and the edge cell charges from its foot as the next token accrues. For a quota that only resets with the period, use an Limit Meter; for usage of a resource, a Segmented Meter.

import { RefillMeter } from '@youj/react'

// What the gateway reported: 38 tokens left at `measuredAt`, refilling 10 a second.
<RefillMeter value={38} updatedAt={measuredAt} capacity={60} refillRate={10} burst={20} />

Give it what you measured: value tokens at updatedAt (a Date.now() time; by default, when value last changed). It counts the refill from there, so there's no need to poll to keep it moving, and a new measurement simply resets the count. The refill stops at capacity, while the meter is off screen and in a hidden tab, and catches up when it's back.

It draws a cell a token up to 60 cells; a larger bucket shares its capacity across 60 (set segments for another count), and the charging cell fills by its share.

Reference

Propsvalue, capacity, refillRate… (8)

Props

RefillMeter props
PropType
valueRequirednumber

Tokens in the bucket when it was measured (at updatedAt).

–
capacityRequirednumber

The bucket's size: the most tokens it holds, so the largest burst it lets through at once.

–
refillRatenumber

Tokens earned back each second.

default 0

0
updatedAtnumber

When value was measured, as a Date.now() time, so the refill counts from then. Default: when value last changed.

–
burstnumber

A marker at this many tokens: the burst a client should keep room for. Under it the lit cells turn to the warning tone.

–
segmentsnumber

How many cells. Default: one per token, up to 60.

–
labelReactNode

The visible name on the start side. Default: the labels' "Tokens".

–
localestring

Default: the YoujProvider locale.

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

Styling

Parts: refill-meter, refill-meter-header, refill-meter-label, refill-meter-value, refill-meter-capacity, refill-meter-gauge, refill-meter-flags, refill-meter-burst-flag, refill-meter-track, refill-meter-cell, refill-meter-fill, refill-meter-burst, refill-meter-reserve, refill-meter-footer, refill-meter-refill, refill-meter-eta and refill-meter-term (the words in the footer). The root has data-state (ok, low or empty) and data-full; each cell has data-state (on, charging or off). The labels take the theme's label voice, and mono capitals in Bezel.

MotionRefill, spend, each cell… · reduced motion

Motion

Motion tokens
MomentTokens
Refillthe edge cell fills from its foot as the next token accrues, then locks in; the clock follows the time scale and stops while full, off screen or hidden
no token

the refill rate

the refill rate
Spendthe cells drain from the edge inward at a constant rate, the whole row spanning the deliberate token, each falling to its foot
duration.deliberate

560ms

560ms
Each cellfalls or rises, and takes its tone
duration.fastease.standard

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

140mscubic-bezier(0.2, 0, 0, 1)
New value mid-draincarries on from the edge on screen, so a burst of updates never jumps
duration.fastease.standard

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

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

Reduced motion

The bucket still refills (it's data), a whole token at a time, with no charging cell and no drain: cells change in place.

Reduced motion

The level still refills, a whole token at a time; there's no charging cell and no drain, and cells change in place.

AccessibilityLabels and assistive technology

Accessibility

  • It's a meter (Base UI Meter) named by its visible label (by default the labels' "Tokens").
  • Its value is spoken as "42 of 60 tokens, refilling 10 a second", with "under the burst of 20" while under the marker and "Empty" when there's nothing left. It updates a whole token at a time, never every frame.
  • The cells, the marker and the charging fill are hidden from assistive tech. The bucket fills from the inline start, so right to left in RTL; its figures keep their order.
  • Its built-in text comes from the labels, so <YoujProvider labels> translates it.