Skip to the content

Props

NameTypeDefaultDescription
variant'live' | 'ageing' | 'estimated' | 'timetable-only' | 'no-signal''live'How fresh the departing vehicle's data is, as Data states names the five states: drawn by the dot, said in words beside it, and, for estimated, timetable-only and no-signal, a "~" before the countdown; timetable-only and no-signal always show an unknown delay. Set on the root as data-variant.
line*'m1' | 'm2' | 'm3' | 'm4' | 'a' | 'b' | 'c' | 'e' | 'f' | 'h' | 'bus' | 'regional'(required)The departure's line, typed as LineBadge's and VehicleDot's line: the badge's colours and the dot's.
lineName*ReactNode(required)The line's short name as riders know it, "5C", "M2" or "A": the badge's label.
destination*ReactNode(required)Where the departure goes, as the operator writes it: "Husum Torv", "Lufthavnen".
countdownnumber—The seconds until the departure leaves, as expected now, delay included. Shown as whole minutes, "4 min", and as "Now" under 45 seconds; left out, or a number that isn't finite, shows "—". Not shown when interval is given.
timestring—The timetabled time of the departure, 24-hour HH:MM, such as '08:14', shown under the countdown, or struck through before the expected time when the row shows one that differs. Left out, the row shows no timetabled time.
expectedstring—The time real-time data expects the departure to leave, 24-hour HH:MM, such as '08:16', as StopTimeline's stops take it. For live, ageing and estimated, shown in the timetabled time's place, after a "~" for estimated, with time struck through before it when the two differ. Not shown for timetable-only or no-signal, whose expected time is unknown, when cancelled, or when interval is given; the row then shows time alone.
delaynumber | null—How late the departure runs, in minutes, as Delay's minutes takes it: positive late, negative early, 0 on time, null unknown. Left out, no Delay, except for a timetable-only or no-signal vehicle, which always shows "—".
intervalnumber | readonly [ number, number ]—The minutes between departures, for a line that runs to an interval rather than to clock times: one number, "Every 3 min", or a range, [3, 4], "Every 3 to 4 min". Shown in place of the countdown, the time and the delay, which the row then leaves out; a number that isn't finite shows "—".
cancelledbooleanfalseThe departure won't run. The row stays, "Cancelled" in place of the dot and the state's word, its countdown or interval and its time struck through, and no delay. Set on the root as data-cancelled.
platformReactNode—Where the departure leaves from at the stop, written whole by the caller as the operator gives it, "Track 4" or "Platform 2": shown after the state's word. Left out, no platform.
nowLabelstringThe locale'sOverrides "Now", shown and heard in place of the countdown under 45 seconds
unknownLabelstringThe locale'sOverrides "Unknown", heard in place of "—" when the countdown or the interval isn't a finite number
timetabledTimeLabelstringThe locale'sOverrides "Timetabled {time}", heard in place of the timetabled time struck through before the expected one, "Timetabled 08:14"; {time} is the timetabled time
cancelledLabelstringThe locale'sOverrides "Cancelled", shown and heard in place of the state's word when cancelled
everyLabelstringThe locale'sOverrides "Every {minutes} min", an interval of one number, "Every 3 min"; {minutes} is the whole minutes
everyRangeLabelstringThe locale'sOverrides "Every {from} to {to} min", an interval's range, "Every 3 to 4 min"; {from} and {to} are the fewest and the most whole minutes
liveLabelstringThe locale'sOverrides "Live", the state's word when variant='live'
ageingLabelstringThe locale'sOverrides "Ageing", the state's word when variant='ageing'
estimatedLabelstringThe locale'sOverrides "Estimated", the state's word when variant='estimated'
timetableOnlyLabelstringThe locale'sOverrides "Timetable only", the state's word when variant='timetable-only'
noSignalLabelstringThe locale'sOverrides "No signal", the state's word when variant='no-signal'
minutesUnitLabelstringThe locale'sOverrides "min", the unit after the countdown's figure and the delay's
minutesLateLabelstringThe locale'sOverrides "min late", heard after the delay's number when late; given to the Delay
minutesEarlyLabelstringThe locale'sOverrides "min early", heard after the delay's number when early; given to the Delay
onTimeLabelstringThe locale'sOverrides "On time"; given to the Delay
delayUnknownLabelstringThe locale'sOverrides "Delay unknown", heard in place of the delay's "—"; given to the Delay
slotProps{ badge?: Omit<LineBadgeProps, "children" | "line" | "size"> | undefined; destination?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined; status?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined; dot?: Omit<VehicleDotProps, "ageingLabel" | "estimatedLabel" | "line" | "liveLabel" | "noSignalLabel" | "size" | "timetableOnlyLabel" | "variant"> | undefined; platform?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; countdown?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; interval?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; schedule?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined; time?: DetailedHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement> | undefined; expected?: DetailedHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement> | undefined; delay?: Omit<DelayProps, "delayUnknownLabel" | "minutes" | "minutesEarlyLabel" | "minutesLateLabel" | "minutesUnitLabel" | "onTimeLabel"> | undefined; }—Props for each part: badge, destination, status, dot, platform, countdown, interval, schedule, time, expected, delay.
variant'live' | 'ageing' | 'estimated' | 'timetable-only' | 'no-signal', default 'live'
How fresh the departing vehicle's data is, as Data states names the five states: drawn by the dot, said in words beside it, and, for estimated, timetable-only and no-signal, a "~" before the countdown; timetable-only and no-signal always show an unknown delay. Set on the root as data-variant.
line (required)'m1' | 'm2' | 'm3' | 'm4' | 'a' | 'b' | 'c' | 'e' | 'f' | 'h' | 'bus' | 'regional', default (required)
The departure's line, typed as LineBadge's and VehicleDot's line: the badge's colours and the dot's.
lineName (required)ReactNode, default (required)
The line's short name as riders know it, "5C", "M2" or "A": the badge's label.
destination (required)ReactNode, default (required)
Where the departure goes, as the operator writes it: "Husum Torv", "Lufthavnen".
countdownnumber, default —
The seconds until the departure leaves, as expected now, delay included. Shown as whole minutes, "4 min", and as "Now" under 45 seconds; left out, or a number that isn't finite, shows "—". Not shown when interval is given.
timestring, default —
The timetabled time of the departure, 24-hour HH:MM, such as '08:14', shown under the countdown, or struck through before the expected time when the row shows one that differs. Left out, the row shows no timetabled time.
expectedstring, default —
The time real-time data expects the departure to leave, 24-hour HH:MM, such as '08:16', as StopTimeline's stops take it. For live, ageing and estimated, shown in the timetabled time's place, after a "~" for estimated, with time struck through before it when the two differ. Not shown for timetable-only or no-signal, whose expected time is unknown, when cancelled, or when interval is given; the row then shows time alone.
delaynumber | null, default —
How late the departure runs, in minutes, as Delay's minutes takes it: positive late, negative early, 0 on time, null unknown. Left out, no Delay, except for a timetable-only or no-signal vehicle, which always shows "—".
intervalnumber | readonly [ number, number ], default —
The minutes between departures, for a line that runs to an interval rather than to clock times: one number, "Every 3 min", or a range, [3, 4], "Every 3 to 4 min". Shown in place of the countdown, the time and the delay, which the row then leaves out; a number that isn't finite shows "—".
cancelledboolean, default false
The departure won't run. The row stays, "Cancelled" in place of the dot and the state's word, its countdown or interval and its time struck through, and no delay. Set on the root as data-cancelled.
platformReactNode, default —
Where the departure leaves from at the stop, written whole by the caller as the operator gives it, "Track 4" or "Platform 2": shown after the state's word. Left out, no platform.
nowLabelstring, default The locale's
Overrides "Now", shown and heard in place of the countdown under 45 seconds
unknownLabelstring, default The locale's
Overrides "Unknown", heard in place of "—" when the countdown or the interval isn't a finite number
timetabledTimeLabelstring, default The locale's
Overrides "Timetabled {time}", heard in place of the timetabled time struck through before the expected one, "Timetabled 08:14"; {time} is the timetabled time
cancelledLabelstring, default The locale's
Overrides "Cancelled", shown and heard in place of the state's word when cancelled
everyLabelstring, default The locale's
Overrides "Every {minutes} min", an interval of one number, "Every 3 min"; {minutes} is the whole minutes
everyRangeLabelstring, default The locale's
Overrides "Every {from} to {to} min", an interval's range, "Every 3 to 4 min"; {from} and {to} are the fewest and the most whole minutes
liveLabelstring, default The locale's
Overrides "Live", the state's word when variant='live'
ageingLabelstring, default The locale's
Overrides "Ageing", the state's word when variant='ageing'
estimatedLabelstring, default The locale's
Overrides "Estimated", the state's word when variant='estimated'
timetableOnlyLabelstring, default The locale's
Overrides "Timetable only", the state's word when variant='timetable-only'
noSignalLabelstring, default The locale's
Overrides "No signal", the state's word when variant='no-signal'
minutesUnitLabelstring, default The locale's
Overrides "min", the unit after the countdown's figure and the delay's
minutesLateLabelstring, default The locale's
Overrides "min late", heard after the delay's number when late; given to the Delay
minutesEarlyLabelstring, default The locale's
Overrides "min early", heard after the delay's number when early; given to the Delay
onTimeLabelstring, default The locale's
Overrides "On time"; given to the Delay
delayUnknownLabelstring, default The locale's
Overrides "Delay unknown", heard in place of the delay's "—"; given to the Delay
slotProps{ badge?: Omit<LineBadgeProps, "children" | "line" | "size"> | undefined; destination?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined; status?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined; dot?: Omit<VehicleDotProps, "ageingLabel" | "estimatedLabel" | "line" | "liveLabel" | "noSignalLabel" | "size" | "timetableOnlyLabel" | "variant"> | undefined; platform?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; countdown?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; interval?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; schedule?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined; time?: DetailedHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement> | undefined; expected?: DetailedHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement> | undefined; delay?: Omit<DelayProps, "delayUnknownLabel" | "minutes" | "minutesEarlyLabel" | "minutesLateLabel" | "minutesUnitLabel" | "onTimeLabel"> | undefined; }, default —
Props for each part: badge, destination, status, dot, platform, countdown, interval, schedule, time, expected, delay.

Use it

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

Ask your agent

search_docs({ query: "DepartureRow" })

Keyboard and ARIA

No Base UI part, so nothing from Base UI here: the row is read, not operated. It takes no focus, and no key does anything (CR-8).

KeyDoesFrom
TabPasses the row by to the next focusable element: nothing in it has a tab stopPerron
ElementRoleAccessible name fromStates announced
rootnone: a generic <div>Not named; its text is read in ordernone
badgenone: LineBadge's <span>Its text, lineNamenone
destinationnone: a generic <div>Its text, destinationnone
dothidden, aria-hidden="true"None: the state's word beside it says the statenone
statusnone: a generic <div>Its text, the state's word: "Live", "Ageing", "Estimated", "Timetable only", "No signal"; "Cancelled" when cancelled; then the platform's textnone
platformnone: a generic <span>Its text, platform: "Track 4"none
countdownnone: a generic <span>Its text: the figure and "min", or "Now"; the "~" is aria-hidden; an unknown countdown's "—" is aria-hidden, and "Unknown" is readnone
intervalnone: a generic <span>Its text: "Every 3 min", "Every 3 to 4 min"; an unknown interval's "—" is aria-hidden, and "Unknown" is readnone
timetime, from the native <time>Its text, "08:14", with dateTime set to the same HH:MM; an estimated time's "~" is aria-hidden; struck through before an expected time, it is aria-hidden, and a visually hidden "Timetabled 08:14" before it is read in its place (CR-16)none
expectedtime, from the native <time>Its text, "08:16", with dateTime set to the same HH:MM; an estimated time's "~" is aria-hidden (CR-16)none
delayDelay's own: generic textDelay's own words: "3 min late", "On time", "Delay unknown"none

A live departure reads "5C, Husum Torv, Live, 4 min, 08:14, On time", and an estimated one "5C, Husum Torv, Estimated, 6 min, 08:16, 3 min late": the word "Estimated" tells the ear what the "~" tells the eye. A cancelled one reads "5C, Husum Torv, Cancelled, 4 min, 08:14": the strike-through is not read, so "Cancelled", read before the countdown, tells the ear what the line through it tells the eye. An interval reads "M2, Lufthavnen, Live, Every 3 to 4 min", and a train with its track "RE, Helsingør, Timetable only, Track 4, 18 min, 08:26, Delay unknown".

A departure two minutes late reads "5C, Husum Torv, Live, 6 min, Timetabled 08:14, 08:16, 2 min late": "Timetabled", read before the struck time, tells the ear what the line through it tells the eye, and the time after it is the one the row shows; an estimated one reads the same after "Estimated", which says the "~" before 08:16 (CR-16).

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 line's colour is named by lineName, read from the badge; the dot's shape by the state's word beside it, read once, since the dot is aria-hidden (CR-6); the "~" by that word, "Estimated", "Timetable only" or "No signal" (CR-4); the countdown by its figure and "min", or "Now"; an unknown countdown by "Unknown" (CR-3); the delay by Delay's own words, and a timetable-only or no-signal vehicle's "—" by "Delay unknown" (CR-5); a cancelled row's strike-through and danger colour by "Cancelled" (CR-13); the timetabled time struck through before an expected one by "Timetabled", and an estimated expected time's "~" by the state's word (CR-16); an interval by its words, read whole (CR-14).
  • Every landmark and named region has an accessible name: none here; the row is no region, and a list of rows is the caller's.
  • Every default label can be overridden: nowLabel, unknownLabel, timetabledTimeLabel, cancelledLabel, everyLabel, everyRangeLabel, the five state labels from liveLabel to noSignalLabel, and Delay's five, minutesUnitLabel, minutesLateLabel, minutesEarlyLabel, onTimeLabel and delayUnknownLabel.
  • Every shape the type accepts renders, in every variant: lineName and destination render a string, an element and a list alike; countdown positive, under 45 seconds, zero, negative, fractional (rounded) and not finite (CR-3); time given and left out; expected given, left out, empty, the same as time and with time left out, in every variant, cancelled and with an interval (CR-16); delay a number, null and left out, in every variant; a long destination wraps under itself (CR-9); interval one number, a range, a range given high to low, a range whose ends round alike, and not finite (CR-14); cancelled with a countdown and with an interval (CR-13); platform a string and an element, beside a long state's word at 320 px (CR-15).
  • A hidden copy kept for animation is aria-hidden, and a collapsed region is inert: none here; nothing animates or collapses. The dot and the "~" are aria-hidden because a word says them, not for animation.
  • Native semantics first: plain divs and spans, a <time> for the time, and the composed components' own; no ARIA but aria-hidden on the dot, the "~", the unknown "—" and the struck timetabled time, which its hidden words say. A cancelled countdown and time, and a timetabled time an expected one replaces, are struck through by CSS, not wrapped in <s> or <del>, which screen readers announce unevenly or not at all; the word "Cancelled" carries it.
  • Focus moves in reading order and returns on close: the row takes no focus; its DOM order, badge, destination, state, platform, countdown or interval, time, expected time and delay, is its reading order on screen.
  • Every target is at least size.target-min square: no target; the row is not pressed (CR-8).
  • Loops stop when the system asks for less motion: none here; nothing moves. A countdown that changes is new props from the screen, not an animation.

Owned strings

The line's name, the destination, the times and the platform are the caller's data; the countdown's words, the interval's words, the state's word and "Cancelled" are the row's own, and Delay's words are Delay's, overridable here through the props above. Each word is a text run of its own, apart from any figure, so expectOwnedStrings reads it as a dictionary value, except the interval's, one template filled with its figures, which expectOwnedStrings matches against the template.

The row adds one owned string, now, "Now", with the Danish "Nu", the Swedish "Nu" and the Norwegian "Nå", outside content design's table of data-state, delay and disruption words. Content design writes "Countdowns under 45 seconds read 'Now'", no key in packages/perron/src/locale/en.ts says it, and it is a countdown's word rather than a data-state, delay or disruption word, as StopTimeline's "Next stop" stayed out of the table.

KeyEnglishOverrideSeen or heard where
now"Now"nowLabelcountdown, seen and heard in place of the figure under 45 seconds; new
unknown"Unknown"unknownLabelcountdown, heard in place of "—" when countdown isn't finite, and interval, when interval isn't, through UnknownValue; an existing key
timetabledTime"Timetabled {time}"timetabledTimeLabelHeard before the time part when an expected time takes its place, in place of the struck time, which is aria-hidden; never seen; new (CR-16)
cancelled"Cancelled"cancelledLabelstatus, seen and heard in place of the dot and the state's word when cancelled; new
every"Every {minutes} min"everyLabelinterval, seen and heard when its ends round alike, "Every 3 min"; new
everyRange"Every {from} to {to} min"everyRangeLabelinterval, seen and heard when its ends differ, "Every 3 to 4 min"; new
minutesUnit"min"minutesUnitLabelcountdown, seen and heard after the figure, "4 min", and the Delay's unit; an existing key
live"Live"liveLabelstatus, seen and heard beside the dot when variant='live'; an existing key
ageing"Ageing"ageingLabelstatus, when variant='ageing'; an existing key
estimated"Estimated"estimatedLabelstatus, when variant='estimated'; an existing key
timetableOnly"Timetable only"timetableOnlyLabelstatus, when variant='timetable-only'; an existing key
noSignal"No signal"noSignalLabelstatus, when variant='no-signal'; an existing key
minutesLate"min late"minutesLateLabeldelay, as Delay's spec gives it; an existing key
minutesEarly"min early"minutesEarlyLabeldelay, as Delay's spec gives it; an existing key
onTime"On time"onTimeLabeldelay, as Delay's spec gives it; an existing key
delayUnknown"Delay unknown"delayUnknownLabeldelay, as Delay's spec gives it; an existing key

now joins en.ts with the JSDoc "A departure's countdown: shown and announced in place of the minutes when it leaves in under 45 seconds.", and its Danish, Swedish and Norwegian in da.ts, sv.ts and nb.ts.

The three later additions brought three more, each new, since no key in en.ts said them, each with a JSDoc in en.ts that says where it shows:

  • cancelled, "Cancelled", with the Danish "Aflyst", the Swedish "Inställd" and the Norwegian "Innstilt". It is named for what it says, not for the row, since StopTimeline's cancelled stops will say the same word; and it joins content design's table, as a word every screen that shows a cancelled trip must agree on, as it does the delay and disruption words.
  • every, "Every {minutes} min", with the Danish "Hvert {minutes}. min", the Swedish "Var {minutes} min" and the Norwegian "Hvert {minutes}. min".
  • everyRange, "Every {from} to {to} min", with "Hvert {from}. til {to}. min", "Var {from} till {to} min" and "Hvert {from}. til {to}. min".

The fourth addition brought timetabledTime, "Timetabled {time}", with the Danish "Planlagt {time}", the Swedish "Ordinarie tid {time}" and the Norwegian "Rutetid {time}", the words departure boards in each language commonly give the timetabled time. It is named for what it says, beside StopTimeline's expectedTime, "Expected {time}", its sibling, since a trip's stops could strike a timetabled time too; it is one template filled by interpolate with the timetabled time, so each locale puts the word where its grammar does; and it is heard only, since the strike-through says it to the eye. Its JSDoc in en.ts says where it is heard. No new word marks the expected time: the "~" before an estimated one is the countdown's, said by the state's word (CR-4), and a time that is neither struck nor estimated needs none.

The interval is one template filled by interpolate, never words joined to the figures in code, as the contract's Words asks of a string that wraps figures, so each locale writes it in its own grammar. Two keys rather than one with an optional range, since a template's words are fixed and a range adds a word, "to", that one number has none of; their names and their {from} and {to} follow DisruptionCard's timeRange and betweenStops, and {minutes} names the minutes as DataStateKey's minutesDuration does, so the library has one name for a figure in minutes. The Danish and Norwegian write the ordinal their sentences write, "hvert 3. minut" and "hvert 3. minutt", the figure with its full stop, with the unit's abbreviation, as content design's "4 min" does; the Swedish ordinal, "var 3:e minut", takes an ending that changes with the figure, "2:a" and "3:e", which a template can't write, so the Swedish writes the figure bare, "var 3 min", as Swedish departure boards commonly write it. Each template carries its own unit, so minutesUnitLabel no longer reaches the interval; everyLabel and everyRangeLabel override it with the rest of the template.

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-1mustWork out variant from the departing vehicle's last report, with the app's thresholds, by default vehicle-dot.live-threshold and vehicle-dot.ageing-thresholdPass live for a departure no vehicle reports on yet: the row would claim more than the data knows; pass timetable-onlyreview
DD-2mustGive countdown as the seconds to the expected departure, worked out from the screen's clock, and update it as the clock movesPass the timetabled seconds for a late departure: the countdown and the delay would disagreereview
DD-3mustGive the timetabled time and let the Delay say how late it runs, and the expected time beside it where real-time data gives onePass the expected time as time as well as a delay: the rider adds the delay twicereview
DD-4shouldPass both times, time and expected, in every state, and let the row choose which to show from variantDraw a times line of your own under the row, or strike or mark a time yourself: the row already follows the state, and two lines would say the time twicereview
DD-5mustSet a stop's departures as a <ul>, each row in its own <li>, under a Section that names the stop or the platformPut a list of rows in a live region: every countdown's change would be readreview
DD-6shouldKeep lineName the short name riders know and destination the place: "5C" towards "Husum Torv"Put the line in destination, "5C Husum Torv": the badge already reads "5C" firstreview
DD-7mustOpen a departure from a Perron link or button the screen sets beside the list, or from the list item made a linkAdd onClick or tabIndex to the row: it has no focus ring, role or pressed lookreview
DD-8mustKeep a cancelled departure in the list with cancelled, where it would have beenDrop it from the list: a rider waiting for it reads its absence as a bus not yet shownreview
DD-9mustGive interval for a line that runs to a headway, such as the Metro, and leave out timePass a countdown worked out from a headway: it claims a departure no timetable setsreview
DD-10mustWrite platform whole, as the board gives it: "Track 4", "Spor 4"Pass the number alone, "4": the rider can't tell a track from a minutereview