Components · Data display
RelativeTime
A localised "3 hours ago" in a <time> element, with the absolute time on hover and focus.
Relative and absolute
import { RelativeTime } from '@rookcom/monarch-react';
const NOW = Date.UTC(2026, 10, 3, 12, 0, 0);
const MIN = 60_000;
const HOUR = 60 * MIN;
const DAY = 24 * HOUR;
<div>
Edited <RelativeTime date={NOW - 3 * MIN} now={NOW} locale="en-GB" timeZone="UTC" />
</div>
<div>
Synced{' '}
<RelativeTime date={NOW - 5 * HOUR} now={NOW} locale="en-GB" timeZone="UTC" />
</div>
<div>
Renews <RelativeTime date={NOW + 2 * DAY} now={NOW} locale="en-GB" timeZone="UTC" />
</div>
<div>
Created{' '}
<RelativeTime
date={NOW - 40 * DAY}
now={NOW}
locale="en-GB"
timeZone="UTC"
absoluteAfter={7 * DAY}
absoluteFormat={{ dateStyle: 'medium' }}
/>
</div>Usage examples
Short, narrow and live
import { RelativeTime } from '@rookcom/monarch-react';
const NOW = Date.UTC(2026, 10, 3, 12, 0, 0);
const MIN = 60_000;
const HOUR = 60 * MIN;
const DAY = 24 * HOUR;
<div>
<RelativeTime
date={NOW - 3 * MIN}
now={NOW}
locale="en"
format="short"
tooltip={false}
/>
</div>
<div>
<RelativeTime
date={NOW - 3 * MIN}
now={NOW}
locale="en"
format="narrow"
tooltip={false}
/>
</div>
<div>
<RelativeTime
date={NOW - DAY}
now={NOW}
locale="en"
numeric="always"
tooltip={false}
/>
</div>Server rendering
import { RelativeTime } from '@rookcom/monarch-react';
const NOW = Date.UTC(2026, 10, 3, 12, 0, 0);
const MIN = 60_000;
const HOUR = 60 * MIN;
<div>
Localised: <RelativeTime date={NOW - 3 * HOUR} now={NOW} locale="de" timeZone="UTC" />
</div>Purpose
Shows when something happened (or will happen) relative to now, in the reader’s language, while keeping the exact moment one hover or Tab away and machine-readable in datetime.
Use when
- Activity feeds, inbox rows, comments and “last synced” labels where recency matters more than the exact time.
- A status that should keep itself current (
live), such as “Updated 2 minutes ago”.
Avoid when
- The exact date is what the reader needs (invoices, contracts, due dates): format the date itself.
- A countdown that must be precise to the second: build it on a timer and an
aria-livepolicy of your own.
Design principles
- The exact time is never only in a
title: the tooltip opens on hover and on keyboard focus and is linked witharia-describedby. - Localised by
Intl.RelativeTimeFormatandIntl.DateTimeFormat; no hand-written “ago” strings. - Server rendering is deterministic when you pass
now; without it, the client corrects the text after hydration instead of warning. - Live updates are quiet: the text changes without a live region, so screen readers are not interrupted every minute.
API reference
import { RelativeTime, formatRelativeTime, relativeTimeParts } from '@rookcom/monarch-react';| Export | Kind | Rendering | Root class |
|---|---|---|---|
RelativeTime | component | client | .mn-relative-time |
formatRelativeTime | utility | client | – |
relativeTimeParts | utility | client | – |
The ref and native attributes go to the <time> element; className goes to the mn-relative-time wrapper that also holds the tooltip.
formatRelativeTime(date, options) and relativeTimeParts(date, now) are exported for places that need the string, such as table exports or aria-labels.
Generated from the TypeScript declarations of packages/react/src/components/data-display/relative-time.
Properties
date and now accept a Date, epoch milliseconds or an ISO 8601 string.
RelativeTime
A `<time datetime>` with localised relative text ("3 hours ago") and the absolute time on hover and focus.
| Prop | Type | Description |
|---|---|---|
date required | DateInput | The moment to describe. A Date, epoch milliseconds or an ISO 8601 string. |
absoluteAfter | number | Show the absolute date instead of relative text once the moment is more than this many milliseconds away, e.g. `7 * 86_400_000` for "a week". |
absoluteFormat | Intl.DateTimeFormatOptions | `Intl.DateTimeFormat` options for the absolute time. Default `{ dateStyle: 'medium', timeStyle: 'short' }`. |
className | string | |
format | "long" | "short" | "narrow" | Unit length: `long` "3 minutes ago", `short` "3 min. ago", `narrow` "3m ago". Default `long`. |
id | string | |
live | number | boolean | Re-render as time passes: `true` picks an interval from the age (5 s for the first minute, then 30 s, 5 min and 1 h); a number is a fixed interval in milliseconds. Default `false`. |
locale | string | BCP 47 locale for both the relative and the absolute text. Default: the runtime locale. |
now | DateInput | The reference time. Pass it from the server (and the same value on the client) for byte-identical server rendering; without it the text is computed from the clock and corrected right after hydration. |
numeric | "auto" | "always" | `auto` writes "yesterday" and "now"; `always` writes "1 day ago". Default `auto`. |
timeZone | string | IANA time zone for the absolute text, e.g. `Europe/London`. Default: the viewer's zone. |
tooltip | boolean | Show the absolute time in a tooltip on hover and keyboard focus. Makes the timestamp a tab stop. Default `true`; set `false` in dense lists where the absolute time is shown elsewhere. |
Variants
| Prop | Values | Description |
|---|---|---|
format | 'long''short''narrow' | “3 minutes ago”, “3 min. ago”, “3m ago” (exact text depends on the locale). |
numeric | 'auto''always' | auto writes “yesterday” and “now”; always writes “1 day ago”. |
tooltip | 'true''false' | Absolute time on hover and focus (a tab stop), or plain text. |
States
| State | Exposed as | Behaviour |
|---|---|---|
| Relative | – | Default: the largest unit that fits, after rounding. |
| Absolute | – | Past absoluteAfter milliseconds the absolute date is shown and the tooltip is dropped. |
| Tooltip dismissed | data-dismissed | Set by Escape while focused; cleared on blur or when the pointer leaves. |
| Invalid date | data-invalid | An unparseable date renders an em dash and no datetime. |
Interaction behaviour
- Hovering the text or the tooltip keeps the tooltip open; the pointer can move onto it (WCAG 1.4.13).
- With
live, the text re-renders every 5 s for the first minute, then every 30 s, 5 min and 1 h as it ages; a number sets a fixed interval. - Passing
nowfreezes the reference time, which turnsliveoff.
Keyboard support
| Keys | Action |
|---|---|
| Tab | Focuses the timestamp and shows the absolute time (when tooltip). |
| Escape | Hides the tooltip without moving focus. |
Accessibility
- Role
- time (with a role="tooltip" description)
- Accessible name
- The relative text; the absolute time is its description through
aria-describedby.
datetimecarries the ISO 8601 instant for machines and assistive technology.- The tooltip shows on
:focus-visible, not only on hover, and can be dismissed with Escape. - Use
tooltip={false}in dense lists to avoid a tab stop per row when the exact time is available elsewhere.
Responsive behaviour
- The text does not wrap. The tooltip is at most 18rem wide and never wider than the viewport minus 2rem.
- The tooltip is positioned with CSS above the text; inside a container that clips overflow it can be cut off, so give such containers room or use
tooltip={false}.
Theme support
- The tooltip uses the inverse surface tokens, like Tooltip, so it reads in light, dark and more-contrast themes.
- The dotted underline uses the current text colour at reduced opacity.
- The tooltip fade is removed under reduced motion.
Do and don't
Do
- Pass the viewer’s
timeZonewhen you know it, so the tooltip shows their local time. - Use
absoluteAfterfor old items, where “5 months ago” is less useful than the date. - Pass
nowwhen rendering on the server if the HTML must be identical to the hydrated result.
Don't
- Do not put essential information only in the tooltip.
- Do not wrap a live RelativeTime in an
aria-liveregion; it would announce every tick. - Do not build “x ago” strings by hand next to it; use
formatRelativeTime.
Related components
- Tooltip: Rich supplementary content on hover and focus.
- ActivityTimeline: Planned feed that shows a RelativeTime per event.
- DescriptionList: Label and value pairs such as “Last updated”.
- DatePicker: Planned input for choosing a date rather than showing one.
Dependencies
| Kind | Depends on |
|---|---|
| npm packages | react |
| Monarch components | None |
Testing coverage
- Unit selection rounds before rolling over (59.6 min reads “1 hour ago”).
- Formats with
Intl.RelativeTimeFormat, includingnumeric,formatand other locales. - Renders
<time datetime>and an absolute tooltip linked byaria-describedby. - Accepts ISO strings, epoch numbers and Date objects.
- Is a tab stop; Escape dismisses the tooltip and blur resets it.
tooltip={false},absoluteAfter,timeZoneand invalid dates.- Live updates tick with fake timers; no ticking without
live. - Forwards the ref and calls consumer handlers.
- Server rendering with
now, and hydration with a different client clock without errors.
| Check | Covered |
|---|---|
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery; Cross-browser axe: /components/relative-time |
Tests: packages/react/src/components/data-display/relative-time