One caption line that names where a panel's data comes from and the time of that data, "Rejseplanen · updated 08:14:05", with an optional second source and its own time, each time worded, when the app gives its own words, by what it is of, "Rejseplanen · position 08:14:05 · times 08:14:20", and two states: paused, and may be out of date. It never counts up, and it never blends two sources into one "last updated".
When to use
Use SourceLine on every panel that shows a source's data, to name the source and the time of its data, and to say when that data is paused or may be out of date.
| Use instead | When |
|---|---|
| Attribution | The credits are the map's, for its tiles and data, with links to their terms |
| TopBar | The time is the moving map's, in the status line along the top of the map |
Props
| Name | Type | Default | Description |
|---|---|---|---|
sources* | readonly [SourceLineSource] | readonly [SourceLineSource, SourceLineSource] | — | Where the panel's data comes from, one source or two, each with its own name and the time of its data, and what that time is of when the app words it, in the order the line shows them. Required. Each source keeps its own time: the line never joins two into one "last updated" (CR-4). |
paused | boolean | false | The panel takes no updates for now: the line starts with "Paused", and each time stays the time of the data the panel shows (CR-5). |
sourceUpdatedLabel | string | The locale's | Overrides "updated {time}", the phrase that gives each source's time; {time} is filled with the source's time |
sourcePausedLabel | string | The locale's | Overrides "Paused", the word that starts a paused line |
sourceOutOfDateLabel | string | The locale's | Overrides "updated {time}, may be out of date", the phrase that gives the time of a source whose outOfDate is set; {time} is filled with the source's time |
sourceLabelOutOfDateLabel | string | The locale's | Overrides "{label}, may be out of date", the phrase that gives the time of a source with its own label whose outOfDate is set; {label} is filled with that label, its {time} filled with the source's time |
className | string | — | Joined after pn-Text pn-SourceLine on the root |
style | CSSProperties | — | Reaches the root |
ref | Ref<HTMLParagraphElement> | — | Reaches the root element |
slotProps | { paused?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; source?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; name?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; separator?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; time?: DetailedHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement> | undefined; } | — | Props for each part: paused, source, name, separator, time. |
sources (required)readonly [SourceLineSource] | readonly [SourceLineSource, SourceLineSource], default —- Where the panel's data comes from, one source or two, each with its own name and the time of its data, and what that time is of when the app words it, in the order the line shows them. Required. Each source keeps its own time: the line never joins two into one "last updated" (CR-4).
pausedboolean, defaultfalse- The panel takes no updates for now: the line starts with "Paused", and each time stays the time of the data the panel shows (CR-5).
sourceUpdatedLabelstring, default The locale's- Overrides "updated {time}", the phrase that gives each source's time;
{time}is filled with the source'stime sourcePausedLabelstring, default The locale's- Overrides "Paused", the word that starts a paused line
sourceOutOfDateLabelstring, default The locale's- Overrides "updated {time}, may be out of date", the phrase that gives the time of a source whose
outOfDateis set;{time}is filled with the source'stime sourceLabelOutOfDateLabelstring, default The locale's- Overrides "{label}, may be out of date", the phrase that gives the time of a source with its own
labelwhoseoutOfDateis set;{label}is filled with that label, its{time}filled with the source'stime classNamestring, default —- Joined after
pn-Text pn-SourceLineon the root styleCSSProperties, default —- Reaches the root
refRef<HTMLParagraphElement>, default —- Reaches the root element
slotProps{ paused?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; source?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; name?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; separator?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; time?: DetailedHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement> | undefined; }, default —- Props for each part:
paused,source,name,separator,time.
Use it
import { SourceLine } from '@mylder/perron/patterns'Ask your agent
search_docs({ query: "SourceLine" })Keyboard and ARIA
SourceLine has no keys of its own and nothing in it is focusable: it is read, not operated.
| Key | Does | From |
|---|---|---|
Tab | Passes the line by to the next focusable element: it has no tab stop (CR-8) | Perron |
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | paragraph, from the native <p> | None; its text is read in place | None |
paused | None: a generic <span> | Not named; "Paused" is read in place | None |
source | None: a generic <span> | Not named; its text is read in place | None |
name | None: a generic <span> | Not named; read in place | None |
separator | None: a generic <span> | Not named; "·" is read as the reader reads it | None |
time | time, from the native <time>; none, a generic <span>, for a phrase that shows no time | Not named; its phrase is read in place | None |
A line reads "Rejseplanen · updated 08:14:05", and a paused one with a doubtful second source "Paused · Rejseplanen · updated 08:14:05 · Vehicle positions · updated 08:09:40, may be out of date". In the app's words: "Rejseplanen · position 08:14:05 · times 08:14:20, may be out of date". A phrase that shows no time, "times from the timetable", or "departures —" while its time is unknown, is the same time part as a <span>: a <time> must carry a date or time, in its dateTime or its text, and a dateTime the phrase doesn't show would tell the ear's tools what the eye isn't told.
The line is no live region: its times change in place without an announcement. The times change every few seconds, which would flood a screen reader, and Accessibility asks that only changes of state be announced, in the screen's own polite live region; a screen that must say a source went out of date or the panel paused says it there.
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: every part is text read in place, the "·" included; paused and out of date are words, not only colours (CR-5, CR-6); nothing is
aria-hidden. - Every landmark and named region has an accessible name: none here; the line is a paragraph, not a landmark or region.
- Every default label can be overridden:
sourceUpdatedLabel,sourcePausedLabel,sourceOutOfDateLabelandsourceLabelOutOfDateLabel, the first two phrases with the same{time}placeholder and the last with{label}; and a source's ownlabeloverrides "updated {time}" for that source. - Every shape the type accepts renders, in every variant:
sourceswith one source and with two, each withoutOfDateleft out,falseandtrue, withpausedoff and on, atimeasHH:MM:SS, asHH:MMand as a date with itsdateTime, a source with and without aname, with and without alabel, alabelwith no{time}, with and without atime, alabelwith{time}and notime, and a name of one long word; every*Labelstring replaces only its own words. SourceLine takes noReactNode. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; nothing animates or collapses. - Native semantics first: a
<p>from Text,<span>s, and a<time>per source whose phrase shows a time; no ARIA of the pattern's own. - Focus moves in reading order and returns on close: nothing takes focus or opens; Tab passes the line by.
- Every target is at least
size.target-minsquare: no target; nothing in the line is pressed. - Loops stop when the system asks for less motion: none here; nothing moves, and a time changes its text without a transition.
Owned strings
Four keys, each in packages/perron/src/locale/en.ts and the Danish, Swedish and Norwegian dictionaries, which agents write; sourceLabelOutOfDate joined the first three with the source's label. All four are named for the source line, since each is worded for it alone: a status line elsewhere, such as the TopBar's "Updated 08:14:05", needs a sentence-case "Updated" under a key of its own. The two phrases wrap the caller's time, so each is one string with a {time} placeholder, filled by interpolate, and its override takes the same placeholder (the contract's Words): Danish, Swedish and Norwegian put the time where their grammar needs it. Both phrases start in lower case because each sits inside the line, after a "·", as "min" and "to" sit inside theirs; "Paused" starts the line, in sentence case. sourceLabelOutOfDate wraps the caller's label filled with its time, so it starts with {label} and its own words follow in each locale, the same words sourceOutOfDate ends with. The names and labels are the caller's, the times are figures, and the "·" holds no letter, which expectOwnedStrings passes.
| Key | English | Override | Seen or heard where |
|---|---|---|---|
sourceUpdated | updated {time} | sourceUpdatedLabel | Each time part of a source that is not out of date, seen and read in place |
sourcePaused | Paused | sourcePausedLabel | The paused part, first in a paused line, seen and read in place |
sourceOutOfDate | updated {time}, may be out of date | sourceOutOfDateLabel | Each time part of a source whose outOfDate is set, seen and read in place |
sourceLabelOutOfDate | {label}, may be out of date | sourceLabelOutOfDateLabel | Each time part of a source with a label whose outOfDate is set, seen and read in place |
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.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | must | Put a SourceLine on every panel that shows a source's data, in the same place, so the reader finds it on every screen | Leave the line off a panel because another panel on the screen has one: Rejseplanen's terms ask for it on every screen | review |
| DD-2 | must | Give each source its own entry with the time of its own data | Pass one source named "Rejseplanen and positions" with one time: a stale feed would read as fresh under the other's time | review |
| DD-3 | must | Word each time by what it is of in label, "position {time}", and leave name off a second fact of the same provider | Write "may be out of date" into a label, or pick the label by outOfDate: set outOfDate and the line adds its own words | review |
| DD-4 | must | Give the time of the data the panel shows, and give it again when that data changes | Give the time the screen last rendered, or the device's clock: the line would say the data is newer than it is | review |
| DD-5 | must | Set outOfDate from the app's own judgement, such as a failed refresh or a time past its limit | Leave a source that failed to refresh without outOfDate: its time alone doesn't tell the reader it stopped | review |
| DD-6 | must | Set paused while the panel takes no updates, and leave each time as it was | Count the time up, or show "8 s ago", while paused: the line would claim a freshness the panel doesn't have | review |
| DD-7 | must | Announce a change of state, such as a source going out of date, in the screen's own polite live region | Make the line a live region: its times change every few seconds and would flood a screen reader | review |
| DD-8 | should | Credit a map's sources with Attribution, with links to their terms | Use the line for the map's credits: it names the data a panel shows and when, not the map's tiles | review |