Skip to content

Lane Meter

Compare workloads across queues or pipeline stages on a shared grid.

import { Lane, LaneItem, LaneMeter } 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 lane meter where a workload moves through states and people compare them at a glance: queued, running, failed and done jobs; builds by stage; requests by region. Every lane has as many cells as the others, so the rows form one ruled grid. A lane with its own capacity (worker slots, a queue's size) fills against it and shows it muted beside the value ("24 / 32"); the other lanes share one scale. For one resource on its own, use a Segmented Meter; for a share of a whole in a table row, use a Share Bar.

import { Button, LaneMeter } from '@youj/react'

<LaneMeter
  lanes={[
    { id: 'queued', label: 'Queued', value: 214, max: 500 },
    { id: 'running', label: 'Running', value: 24, max: 32, tone: 'accent', active: true },
    { id: 'failed', label: 'Failed', value: failed.length, tone: 'danger', items: failed, action: <Button size="xs" variant="secondary">Retry all</Button> },
    { id: 'done', label: 'Done', value: 12480, max: 16000, tone: 'success' },
  ]}
  format={{ notation: 'compact', maximumFractionDigits: 1 }}
  onItemAction={(item) => retry(item)}
/>

Each lane takes a label, a value and, optionally, its own max, a tone (a status, the accent, a chart color or neutral, the ink), active for work in progress and an action for its end. segments sets the cells per lane (default 32) and format takes Intl.NumberFormat options for the values.

Reference

Propslanes, max, segments… (9)

Props

LaneMeter props
PropType
lanesRequiredreadonly Lane[]–
maxnumber

The scale shared by lanes without their own max. Default: the largest of their values.

–
segmentsnumber

Cells per lane.

default 32

32
onItemAction(item: LaneItem, lane: Lane) => void

Makes each item cell a button that calls this.

–
itemActionLabelstring

The items' action, spoken with each ("Retry job-8f2a"). Default: the labels' "Retry".

–
formatIntl.NumberFormatOptions

Intl.NumberFormat options for the values. Default: plain counts.

–
localestring

Default: the YoujProvider locale.

–
labelstring

The meter's accessible name. Default: the labels' "Queue load".

–
soundboolean

With sound on, an item action plays tap. false keeps it silent.

default true

true
Other props pass through: extends ComponentProps<'div'>.
StylingParts and data attributes

Styling

Parts: lane-meter, lane-meter-lanes, lane-meter-lane, lane-meter-meter, lane-meter-label, lane-meter-value, lane-meter-max, lane-meter-track, lane-meter-cell (with data-state on or off), lane-meter-item, lane-meter-glint, lane-meter-action and lane-meter-tooltip. Each lane has data-tone and, when active, data-active. The labels take the theme's label voice (mono capitals in Basalt). Under 30rem of width, each lane stacks its label and value over the cells.

MotionFill, new value, active lane… · reduced motion

Motion

Motion tokens
MomentTokens
Fillwhen the meter scrolls into view, each lane lights its cells one after another at a constant rate, a stagger step after the lane above
duration.deliberate

560ms

560ms
New valuelights or darkens the cells between the edge on screen and the new one, in order
duration.fastease.standard

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

140mscubic-bezier(0.2, 0, 0, 1)
Active lanea soft light crosses its lit cells and rests, only while the meter is on screen
duration.deliberate

560ms

560ms
Item leavesshrinks and fades out while the others glide to their new cells
duration.fastease.enter

140ms · cubic-bezier(0.16, 1, 0.3, 1)

140mscubic-bezier(0.16, 1, 0.3, 1)

Reduced motion

Cells are lit in place, the active lane has no traveling light, and items change at once.

Reduced motion

Every cell is lit at once, the active lane's light is off, and items appear and leave without animation.

AccessibilityKeyboard

Accessibility

  • The meter is a group named by label (default "Queue load"). Each lane is a meter named by its visible label; a lane with its own max is spoken "24 of 32".
  • Item buttons sit in a group named by their lane. The lane is one tab stop; arrow keys follow the reading direction.
  • The cells are hidden from assistive tech; they fill from the inline start, so right to left in RTL.