Skip to content

Meters & limits

How much is used and how much is left: limits, allowances, dials, capacity, stock, envelopes, streaks and goals.

Installation & usage

npx @youj/cli add app-limit-meters

Also installs alert, async-button, badge, button, card, dropdown-menu, empty, icon-more-horizontal, refill-meter, select, skeleton, sparkline, typography, use-announcer, youj-core, youj-ui-core.

The CLI copies the block to blocks/app/limit-meters.tsx with every component it uses, so it’s yours to edit.

Every prop is optional and falls back to the demo, so it renders as you see it until you pass your own. Give it your data, rewrite or translate its strings through copy, and connect its actions:

limitMeters-view.tsx
'use client'

import { LimitMeters, type LimitMetersProps } from '@/blocks/app/limit-meters'

export function LimitMetersView({ limiters, kinds }: Pick<LimitMetersProps, 'limiters' | 'kinds'>) {
  return (
    <LimitMeters
      limiters={limiters}
      kinds={kinds}
      copy={{ title: 'Rate limits' }}
      onRaiseLimit={async (limiter) => {
        // await your API here; the block shows progress until it settles
      }}
      onRetry={() => {
        // your code
      }}
    />
  )
}

Reference

Props15 props

Props

LimitMeters props
PropType
themeThemeInput

Wraps the block in this theme. Default: the theme around it.

–
embeddedboolean

Inside another app: a section named by an h2, without the page around the card.

default true

true
fillboolean

Take the whole width it's given instead of stopping at its natural width (544px at 100% scale).

default false

false
copyPartial<LimitMetersCopy>

Any of the card's strings, to rewrite or translate.

–
limitersLimitMetersLimiter[]

What there is to choose from, with its figures now; re-render with fresh ones to keep it live. Default: demo limiters, driven by simulated traffic.

–
kindsLimitMetersKind[]

The groups the limiters are listed under in the picker, in order; a limiter's kind is one's id.

default API keys and Endpoints

API keys and Endpoints
format{ rate?: (value: number) => string }

Writes the rate figures (the throughput, the limit and the policy line) as text. Default: the locale's number format. Units come from copy.

–
defaultLimiterstring

The limiter shown first. Default: the first.

–
onRaiseLimit(limiter: LimitMetersLimiter) => Promise<unknown> | unknown

Raises a limiter's limit; resolve when it's applied. Default: a short demo wait.

–
loadingboolean

Skeletons in place of the figures while your data loads.

default false

false
errorReactNode

Shown in place of the figures when they fail to load, with Retry when onRetry is set. Default: none.

–
onRetry() => void

Retries after an error. Default: none.

–
emptyReactNode

Replaces the message when limiters is empty. Default: copy.emptyTitle and copy.emptyDescription.

–
demoMarkerboolean

Shows a dashed "Demo data" badge while the card runs on simulated traffic (no limiters passed).

default true

true
localestring

Formats its numbers and dates (BCP 47). Default: copy.locale, else the app's locale (YoujProvider), else en-US.

–
Strings31 keys for copy

Strings

copy takes any of these keys; the rest keep their defaults. A key whose text holds a value (a count, a name) takes a function.

titlescopemoreviewLogscopyIdrefilllimiterthroughputperMinutestatustokensthrottledCodethrottledWindowthrottledChartlimitcapacityacceptedperMinuteUnittokensUnitpolicysendBurstraiseraisingraisedrefilleddemoDataloadingretryemptyTitleemptyDescriptionlocale
Built from11 components
Accessibilitymeters, toggles, keyboard, motion

Accessibility

Limit meters has a labelled picker, and the bucket is a meter named by its label.

Health dial labels its window control and the signals section, and each row's action button names its part ("Shift traffic from us-east-2"). Loading is announced, and an error says why with a Retry button. The stories show other worlds, with their own names and words.

Tiered capacity draws its columns as a picture (aria-hidden); the region picker is a labelled segmented control with spoken buttons, the legend is a list, and a hidden table holds every figure.

Bin rack draws the rack as a decorative image and lists every bin as a button with its state and when it runs out (for example "Caps C-12, 6 left, low, empty in ~14 min"); focusing a bin tags it on the drawing. Low and empty are named in words as well as colored and dashed, and the auto-call switch is labelled. The stories show other worlds, with their own names and words.

Envelopes are a labelled group; each envelope is named with what is left (or by how much it is over). Money moves by drag or by keyboard: Space picks an envelope up, the arrow keys choose the target and the amount, Enter moves it and Escape cancels, with a hidden hint describing the keys. The Pace budget treemap has one tab stop, with the arrow keys and Home and End moving between cells. The plan is a list of switches, each beside the step it applies.

In Streaks each item in the list is a button with aria-pressed and a name, and the Mark done control is a labelled toggle for today. The list has its own label.

Each chart has a name and a one-sentence summary, and the metric chart's numbers are also in a real table behind View data. Wherever you can scrub a chart (the KPI tiles and the metric chart), it is a slider: Left and Right step a bucket, Home and End jump to either end, Escape lets go, and each position is read out as a sentence with the date, the figures and the change. The tile and chart headers update with it.

Under reduced motion values change in place.