Skip to content

Severity Timeline

Trace an incident’s events, durations and resolution milestones.

import { SeverityEvent, SeverityTimeline } 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 severity timeline for the story of one incident: the alerts that fired, the pages, the deploys and rollbacks, and the moments it was acknowledged, mitigated and resolved. Every row has its clock time and how long after the start it came, a node on a rail, a soft SEV chip and the title. Beside it runs the ribbon, a thin track spanning the whole incident on every row, with the event's own bar at its offset and length and each milestone as a dashed rule on every row, so the phases line up down the list and you can see at a glance what was still firing when someone took command. For a project's general activity feed, use a Timeline.

import { SeverityTimeline, type SeverityEvent } from '@youj/react'

const events: SeverityEvent[] = [
  { id: 'alert', at: start, severity: 2, title: 'Error rate above 5% on checkout-api', actor: 'pagerbot', ongoing: true },
  { id: 'ack', at: start + 3 * 60_000, milestone: 'acknowledged', title: 'M. Oyelaran took command' },
  { id: 'rollback', at: start + 11 * 60_000, severity: 3, title: 'Rolled back to v2.14.3', duration: 4 * 60_000 },
  { id: 'mitigated', at: start + 16 * 60_000, milestone: 'mitigated', title: 'Authorisations recovering' },
]

<SeverityTimeline events={events} timeZone="UTC" />

Pass events in any order: they're shown oldest first. at is a time in ms. An event with duration draws a bar, one with ongoing runs to now (or to the resolution), and one with neither draws a tick. severity (1 is the worst) draws the SEV chip and tones the node and the bar: SEV1 in danger, SEV2 in warning, SEV3 in the accent and SEV4 neutral. An event without a severity can take a tone instead (a chart color for its kind, as the Threat case card colors each step of an attack chain); without either it is neutral.

Reference

Propsevents, start, end… (8)

Props

SeverityTimeline props
PropType
eventsRequiredreadonly SeverityEvent[]–
startnumber

When the incident began, in ms. Default: the first event.

–
endnumber

When it ended, in ms. Default: the resolved milestone, else it's open and runs to now.

–
nownumber

The current time, in ms. Default: a live clock (every second while the incident is open).

–
localestring

Default: the YoujProvider locale.

–
timeZonestring

Clock times in this zone, e.g. "UTC". Default: the browser's.

–
labelstring

The list's accessible name. Default: the labels' "Incident timeline".

–
formatTime(ms: number) => string

Formats clock times. Default: 24-hour HH:mm in the locale.

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

Styling

Parts: severity-timeline, severity-timeline-axis, severity-timeline-list, severity-timeline-event, severity-timeline-time, severity-timeline-node, severity-timeline-body, severity-timeline-severity, severity-timeline-label (a milestone's word, in the theme's label voice), severity-timeline-title, severity-timeline-detail, severity-timeline-actor, severity-timeline-value (the since-start and duration figures), severity-timeline-ribbon, severity-timeline-bar, severity-timeline-rule, severity-timeline-now and severity-timeline-empty. The root has data-state (open or closed); each event has data-severity, data-milestone and data-ongoing. Under 34rem of its own width (a container query) the ribbon drops under each row.

MotionEvent arrives, node, bar… · reduced motion

Motion

Motion tokens
MomentTokens
Event arrivesthe row takes its slot and fades down while the rows below glide (PresenceList)
duration.baseease.enter

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

220mscubic-bezier(0.16, 1, 0.3, 1)
Nodea new event’s dot or diamond lands, with no overshoot
spring.snappy

0.2s, bounce 0

0.2s, bounce 0
Bargrows from its start edge; bars and rules move when the window re-ranges (clip-path and translate only)
duration.slowease.standard

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

340mscubic-bezier(0.2, 0, 0, 1)
Live endan ongoing bar’s end breathes while the incident is open
duration.deliberateease.standard

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

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

Reduced motion

Rows, nodes and bars appear in place, the window re-ranges at once and the live end holds still.

Reduced motion

Everything is drawn in place: new rows appear without a fade or a glide, bars take their length at once and the live end holds still.

Accessibilityannouncements

Accessibility

  • It's an ordered list (ol) named by label (default "Incident timeline"), oldest first.
  • Each row reads in order: its time (a time element), its severity spoken in full ("Severity 2", the chip's SEV2 is hidden), the title, the detail, how long it lasted ("12 minutes, Ongoing") and how long after the start it came ("6 minutes after start").
  • The ribbon, the nodes and the rail are hidden from assistive tech: the text carries what they show.
  • Ticking durations aren't announced. Announce new events from your app where it matters, as the incident block does.