Skip to the content
  1. Svanemøllen PassedOn time
  2. Nordhavn Passed 1 min early
  3. ØsterportNext stop 2 min late
  4. Nørreport 3 min late
  5. Vesterport 3 min late

Props

NameTypeDefaultDescription
stops*StopTimelineStop[](required)The trip's stops, first to last: each one's name, and optionally its timetabled time, its expected time, its delay in minutes and whether the call is cancelled.
line'm1' | 'm2' | 'm3' | 'm4' | 'a' | 'b' | 'c' | 'e' | 'f' | 'h' | 'bus' | 'regional'—The line or mode whose colour the rail and the markers take, as StationIcon's line. Left out, the rail and markers are neutral.
nextStopIndexnumber—The index in stops of the vehicle's next stop. The stops before it are passed and the ones after it upcoming; an index past the last stop means the trip is over and every stop passed. Left out, the vehicle's place is unknown and no stop is passed or next.
nextStopLabelstringThe locale'sOverrides "Next stop"
passedLabelstringThe locale'sOverrides "Passed", heard after a passed stop's name
cancelledLabelstringThe locale'sOverrides "Cancelled", seen under a cancelled stop's name and heard after it.
expectedTimeLabelstringThe locale'sOverrides "Expected {time}", heard in place of a stop's "~" and expected time, "Expected 08:16"; {time} is the expected time
minutesUnitLabelstringThe locale'sOverrides "min", the unit after each delay's figure; given to every Delay
minutesLateLabelstringThe locale'sOverrides "min late", heard after the number when late; given to every Delay
minutesEarlyLabelstringThe locale'sOverrides "min early", heard after the number when early; given to every Delay
onTimeLabelstringThe locale'sOverrides "On time"; given to every Delay
delayUnknownLabelstringThe locale'sOverrides "Delay unknown", heard in place of "—"; given to every Delay
classNamestring—Merged after pn-StopTimeline on the root
styleCSSProperties—Reaches the root
refRef<HTMLOListElement>—Reaches the root
stops (required)StopTimelineStop[], default (required)
The trip's stops, first to last: each one's name, and optionally its timetabled time, its expected time, its delay in minutes and whether the call is cancelled.
line'm1' | 'm2' | 'm3' | 'm4' | 'a' | 'b' | 'c' | 'e' | 'f' | 'h' | 'bus' | 'regional', default —
The line or mode whose colour the rail and the markers take, as StationIcon's line. Left out, the rail and markers are neutral.
nextStopIndexnumber, default —
The index in stops of the vehicle's next stop. The stops before it are passed and the ones after it upcoming; an index past the last stop means the trip is over and every stop passed. Left out, the vehicle's place is unknown and no stop is passed or next.
nextStopLabelstring, default The locale's
Overrides "Next stop"
passedLabelstring, default The locale's
Overrides "Passed", heard after a passed stop's name
cancelledLabelstring, default The locale's
Overrides "Cancelled", seen under a cancelled stop's name and heard after it.
expectedTimeLabelstring, default The locale's
Overrides "Expected {time}", heard in place of a stop's "~" and expected time, "Expected 08:16"; {time} is the expected time
minutesUnitLabelstring, default The locale's
Overrides "min", the unit after each delay's figure; given to every Delay
minutesLateLabelstring, default The locale's
Overrides "min late", heard after the number when late; given to every Delay
minutesEarlyLabelstring, default The locale's
Overrides "min early", heard after the number when early; given to every Delay
onTimeLabelstring, default The locale's
Overrides "On time"; given to every Delay
delayUnknownLabelstring, default The locale's
Overrides "Delay unknown", heard in place of "—"; given to every Delay
classNamestring, default —
Merged after pn-StopTimeline on the root
styleCSSProperties, default —
Reaches the root
refRef<HTMLOListElement>, default —
Reaches the root

Use it

import { StopTimeline } from '@mylder/perron/patterns'

Ask your agent

search_docs({ query: "StopTimeline" })

Keyboard and ARIA

No Base UI part, so nothing from Base UI here: the timeline is read, not operated. It takes no focus, and no key does anything.

KeyDoesFrom
NoneThe timeline is not focusable or operable; Tab passes it byPerron
ElementRoleAccessible name fromStates announced
rootlist, from the native <ol>None of its own; the caller's aria-labelledby, such as the detail panel's heading, when it gives oneIts number of items, from the <ol>
stoplistitem, from the native <li>Its text, read in order: the name, "Passed" or "Next stop", "Cancelled", the time, "Expected" and the expected time, the delay's wordsaria-current="step" on the next stop
rail and markerhidden, aria-hidden="true"None: decorative; the words say what they showNone
nexttextThe owned string "Next stop"None
passedtext, visually hiddenThe owned string "Passed"None
cancelledtextThe owned string "Cancelled"; the strike-through is not read, so the word says itNone
timetime, from the native <time>Its text, "08:14", with dateTime set to the same HH:MMNone
expectedgeneric text, holding a time, from the native <time>The owned string "Expected {time}" filled with the time, "Expected 08:16", visually hidden; the "~" and the <time>, its dateTime the same HH:MM, are aria-hidden, so the time is heard onceNone
delayDelay's own: generic textDelay's own words: "3 min late", "On time", "Delay unknown"None

A next stop reads "Nørreport, Next stop, 08:14, 3 min late", and a passed one "Forum, Passed, 08:10, On time". With an expected time it reads "Nørreport, Next stop, 08:14, Expected 08:17, 3 min late": the word "Expected" tells the ear what the "~" tells the eye, as the state's word does for DepartureRow's "~". A cancelled call reads "Vesterport, Cancelled, 08:16": "Cancelled", read before the time, tells the ear what the line through it tells the eye, as in DepartureRow's "5C, Husum Torv, Cancelled, 4 min, 08:14".

The next stop's list item carries aria-current="step" beside its "Next stop" words: it is the attribute ARIA gives for the current step in a sequence, so a screen reader names the stop as current when it lands on it from anywhere in the list, while the words say why.

What axe won't catch, from the contract, each with how this component meets it:

  • Everything the eye is told, the ear is told, for every shape each prop accepts: the filled marker and the "Next stop" words say which stop is next, heard as "Next stop" and aria-current="step"; the set-back colour of a passed stop is heard as "Passed"; a cancelled call's danger colour and struck-through times are heard as "Cancelled", before the times (CR-14); the "~" before an expected time is heard as "Expected", with the time (CR-15); the rail and the line's colour are decoration, the line named in words by the panel around the timeline; each Delay says its delay in words; a stop with no time or delay shows and says nothing for it; with no nextStopIndex, nothing is set back or marked, and nothing is said
  • Every landmark and named region has an accessible name: none here; the root is a list, not a region, and takes the caller's aria-labelledby when the panel names it
  • Every default label can be overridden: nextStopLabel, passedLabel, cancelledLabel and expectedTimeLabel, and Delay's five, minutesUnitLabel, minutesLateLabel, minutesEarlyLabel, onTimeLabel and delayUnknownLabel
  • Every shape the type accepts renders, in every variant: an empty stops renders an empty list; one stop renders with no rail; each stop with and without time, expected and delay, and delay as a number and null; a stop with only an expected, and an empty expected, which shows nothing; cancelled true and false, on a passed, a next and an upcoming stop, with and without an expected; a trip with no expected keeps no column for one; nextStopIndex left out, at the first stop, in the middle, at the last stop and past it, negative or not a whole number (CR-2); every line value and none; a long name wraps under itself
  • A hidden copy kept for animation is aria-hidden, and a collapsed region is inert: none here; nothing animates or collapses. The rail and marker are aria-hidden because they are decoration, not copies
  • Native semantics first: <ol> and <li> for the ordered stops, <time> for each time and each expected time, aria-current the one attribute ARIA adds, and aria-hidden on the decoration and the "~". A cancelled call's times are struck through by CSS, not wrapped in <s> or <del>; the word "Cancelled" carries it
  • Focus moves in reading order and returns on close: the timeline takes no focus
  • Every target is at least size.target-min square: no target; the stops are not pressed (CR-8)
  • Loops stop when the system asks for less motion: none here; nothing moves

Owned strings

The stop names, times, expected times and delays are the caller's data; the words of a stop's place in the trip, "Cancelled" and "Expected" are the pattern's own, and Delay's words are Delay's, overridable here through the props above. Each word is a text run of its own, so expectOwnedStrings reads it as a dictionary value, and the heard expected time is one template filled with the time, which expectOwnedStrings matches against the template.

KeyEnglishOverrideSeen or heard where
nextStop"Next stop"nextStopLabelnext, seen under the next stop's name and read after it
passed"Passed"passedLabelpassed, heard after each passed stop's name; never seen
cancelled"Cancelled"cancelledLabelcancelled, seen under a cancelled stop's name and read after it; DepartureRow's key, reused
expectedTime"Expected {time}"expectedTimeLabelexpected, heard in place of each "~" and expected time, "Expected 08:16"; never seen; new
minutesUnit"min"minutesUnitLabelEach delay, as Delay's spec gives it; an existing key in packages/perron/src/locale/en.ts
minutesLate"min late"minutesLateLabelEach delay, as Delay's spec gives it; an existing key
minutesEarly"min early"minutesEarlyLabelEach delay, as Delay's spec gives it; an existing key
onTime"On time"onTimeLabelEach delay, as Delay's spec gives it; an existing key
delayUnknown"Delay unknown"delayUnknownLabelEach delay, as Delay's spec gives it; an existing key

nextStop and passed are new, each with a JSDoc line like its neighbours in en.ts, and agents write their Danish, Swedish and Norwegian. Neither is a data-state, delay or disruption word, so neither joins content design's table.

cancelled is DepartureRow's key, "Cancelled", already in content design's table, whose JSDoc names a trip's stop as well as a departure: a cancelled call and a cancelled departure say the same word on every screen. expectedTime came with the expected time, "Expected {time}", with the Danish "Forventet {time}", the Swedish "Beräknad {time}" and the Norwegian "Forventet {time}": a template filled by interpolate, never the word set beside the time in code, as the contract's Words asks of a string that wraps the caller's words, so a locale can put the time where its grammar needs it. It is named for what it says, as DisruptionCard's fromTime and untilTime are. It is its own word, not the data state's "Estimated": "Estimated" says how a vehicle was placed, and an expected time can come from a live vehicle. Like passed it is heard and never seen, since the "~" says it to the eye, and it is not a data-state, delay or disruption word, so it does not join content design's table.

The next stop shows "Next stop" in words under its name, as well as its filled marker, and a passed stop says "Passed" to the ear only: StationIcon's spec asks that a filled stop's meaning be said in words beside it, and a sighted rider learns the filled marker from the words; a passed stop's set-back colour is plain to the eye in its place in the list, so "Passed" in every passed row would only crowd it, while the ear, which can't see the colour, hears it.

Do and don't

For a caller using the pattern, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.

RuleLevelDoDon'tChecked by
DD-1mustName the line in words around the timeline, such as in the panel's header with a LineBadge, because the rail's colour is decorationRely on the rail's colour to say which line runs the trip: colour is never alone (Accessibility)review
DD-2mustLeave nextStopIndex out when no real-time data places the vehicle, so no stop claims to be nextGuess a next stop from the timetable and pass it: it claims more certainty than the data has (Content design)review
DD-3mustPass delay: null for a stop whose delay no real-time data says, and leave delay out where no delay belongsPass 0 for an unknown delay: "On time" claims a certainty the data doesn't havereview
DD-4mustGive the timetabled time and let Delay say how late the vehicle runs; give the expected time as expected where real-time data says itPass the expected time as time as well as a delay: the rider adds the delay twicereview
DD-5mustKeep a cancelled call in stops with cancelled: true, where the vehicle would have calledDrop it from the list: a rider waiting there reads its absence as a stop not yet shownreview
DD-6mustLeave expected out where no real-time data gives oneCopy the timetabled time into expected: the "~" claims an estimate the data doesn't havereview
DD-7mustPoint the root's aria-labelledby at the panel heading that names the tripWrap the timeline in a live region: every update rereads the whole tripreview
DD-8shouldPass only the stops the screen needs, such as the next few, when the trip is longRestyle the markers or the rail's width through className, which breaks the ring's and the rail's matching weightreview