Skip to content

Distribution Strip

Show a distribution as dots on a log scale, with percentile marks and a target, such as request latency.

import { DistributionStrip } 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 distribution strip where the question is "how slow is it, really": a service's or a route's latency, a job's run time. Every sampled request is a dot on a log-scaled strip, stacked into rows where they crowd, so the swarm is fattest where most requests land and the tail stays visible dot by dot. The percentiles (p50, p90 and p99 by default) are flagged hairlines, and the objective is a dashed line: past it the strip is hatched and its dots turn to the warning tone. For one latency against a limit, use a Segmented Meter; for a trend over time, a Chart.

import { DistributionStrip } from '@youj/react'

// Latencies in milliseconds, one per sampled request.
<DistributionStrip samples={latencies} slo={300} label="checkout-api · last 24h" />

The axis runs over the whole decades around the samples (10 ms to 1 s for samples between 22 and 990 ms), with a tick for every step of each decade; pass domain for other ends. Latencies read in milliseconds, and in seconds from 1 s, in the provider's locale; pass format for your own. The header counts the share of samples within slo.

percentileOf(samples, p) gives the same interpolated percentile the strip flags, for a headline figure beside it.

Reference

Propssamples, slo, percentiles… (7)

Props

DistributionStrip props
PropType
samplesRequiredreadonly number[]

Sampled request latencies, in milliseconds.

–
slonumber

The latency objective, in milliseconds: a dashed line, the strip past it hatched, and the share of samples within it in the header.

–
percentilesreadonly number[]

The percentiles to mark, 0–100.

default DEFAULT_PERCENTILES

DEFAULT_PERCENTILES
domainreadonly [number, number]

The axis's ends, in milliseconds. Default: the whole decades around the samples.

–
rowsnumber

How many rows the dots stack into where they crowd; an even number gets one more, so the swarm has a middle.

default 11

11
format(ms: number) => string

Formats a latency for the flags, the ruler, the objective and the summary. Default: milliseconds, and seconds from 1 s, in the locale.

–
labelstring

The visible name over the strip, which also names the figure. Default: the labels' "Latency distribution".

–
Other props pass through: extends ComponentProps<'figure'>.
StylingParts and data attributes

Styling

Parts: distribution-strip, distribution-strip-header, distribution-strip-label, distribution-strip-within, distribution-strip-within-label, distribution-strip-value, distribution-strip-empty, distribution-strip-chart, distribution-strip-plot, distribution-strip-over, distribution-strip-dot, distribution-strip-slo, distribution-strip-slo-flag, distribution-strip-marker, distribution-strip-line, distribution-strip-flag, distribution-strip-axis, distribution-strip-tick, distribution-strip-tick-label and distribution-strip-summary. A dot past the objective has data-over, a marker its data-percentile, and a decade tick data-major. The labels take the theme's label voice (mono capitals in Basalt).

MotionReveal, wave, markers… · reduced motion

Motion

Motion tokens
MomentTokens
Revealthe dots rise from under the baseline and fade in when two fifths of the strip scroll into view
duration.slowease.enter

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

340mscubic-bezier(0.16, 1, 0.3, 1)
Waveeach dot waits for its place along the axis, so the rise sweeps from the start
no token

the base token, spread from start to end

the base token, spread from start to end
Markersthe percentile hairlines and their flags glide in from the inline start, and retarget from where they are
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
New samplesthe dots are matched by rank, so each quantile slides to where it now falls, in the same wave
duration.slowease.enter

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

340mscubic-bezier(0.16, 1, 0.3, 1)
Share within the objectivecounts to its new value
duration.deliberateease.emphasized

560ms · cubic-bezier(0.6, 0, 0.1, 1)

560mscubic-bezier(0.6, 0, 0.1, 1)
Flagsshift apart as their lines close in
duration.baseease.standard

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

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

Reduced motion

Drawn in place; new samples land at once.

Reduced motion

The dots and markers are drawn in place, and new samples land at once.

AccessibilityARIA

Accessibility

  • A figure named by its visible label (by default the labels' "Latency distribution") and described by a text summary: how many requests were sampled, each percentile's latency, and the share within the objective ("97.4% within the 300 ms SLO.").
  • The dots, the ruler and the hatch are decorative (aria-hidden); the flags and the header are text.
  • With no samples it says "No data", and there's no summary.
  • The axis runs from the inline start, so right to left in RTL; the flags' figures keep their order.
  • Its built-in text comes from the labels, so <YoujProvider labels> translates it.