The time Element and Relative Timestamps

Permalink to "The time Element and Relative Timestamps"

Data interfaces are full of timestamps: “Updated 5 minutes ago”, “Created 3 days ago”, “Last login yesterday”. Relative times are friendly for recency and terrible for precision. The real time usually hides in a title tooltip that keyboard and touch users cannot reach and most screen readers do not read. And because relative text changes on its own, careless implementations announce “4 minutes ago… 5 minutes ago” to screen reader users every minute.

This guide belongs to accessible date & time data.

Spec reference

Permalink to "Spec reference"
  • HTML time element — represents a date or time; the datetime attribute holds a machine-readable value (ISO 8601, for example 2026-10-02T10:42:00+02:00). Screen readers read the element’s text content, not the attribute.
  • SC 1.3.1 Info and Relationships (A) — the absolute time is information; it must be programmatically available, not only in a hover tooltip.
  • SC 1.4.13 Content on Hover or Focus (AA) — a custom tooltip with the absolute time must be dismissible, hoverable and persistent.
  • SC 2.2.2 Pause, Stop, Hide (A) — auto-updating content is in scope; silent text updates are acceptable, announced ones are not.
  • SC 4.1.3 Status Messages (AA) — relative time ticking is not a status message; do not announce it.
title tooltip versus accessible absolute time Comparison: the title attribute hides the absolute time from keyboard, touch and most screen reader users; accessible patterns show it in text, in a description or in a toggletip. title tooltip versus accessible absolute time✗ title="2 Oct 2026, 10:42" onlyMouse users only, after a delayNot read by most screen readersUnreachable on touchCannot be copied✓ Absolute time available to everyoneVisible in a column, description or toggletipRead as text or descriptionTap or focus to revealSelectable text

When to use — and when not to

Permalink to "When to use — and when not to"

Use relative times for recency in lists and feeds, where “how long ago” is the question — activity logs, last-updated stamps, comment threads. Pair them with absolute times wherever precision matters.

Use absolute times in tables where users compare, sort or audit — transaction times, due dates, timestamps in logs. “3 days ago” cannot be compared at a glance with “2 days ago” across a hundred rows, and it means different things depending on when you read it.

The misapplication: a “Created” column showing only relative times, sorted by the hidden absolute value. Screen reader users hear “3 days ago, 3 days ago, 4 days ago” with no way to distinguish rows.

Choosing relative or absolute Flow: is recency the question? Use relative text with an absolute time available. Will users compare, sort or audit? Use absolute. Is the time older than a week? Switch to an absolute date. Choosing relative or absoluteWhat is the question?"how recent?" or "exactly when?"decide per columnRecency"5 minutes ago" with absolute on demandfeeds, activity, freshnessPrecision"2 Oct 2026, 10:42"tables, audits, sortingOlder than about a weekabsolute date even in feeds"3 weeks ago" is vague

Annotated code example

Permalink to "Annotated code example"
<!-- Relative text visible; absolute time in a description users can reach (SC 1.3.1) -->
<td>
  <time datetime="2026-10-02T10:42:00+02:00" aria-describedby="t-88-abs">5 minutes ago</time>
  <span id="t-88-abs" class="visually-hidden">2 October 2026 at 10:42 CEST</span>
</td>

<!-- Or: both visible, compact -->
<p class="updated">Updated <time datetime="2026-10-02T10:42:00+02:00">10:42</time> (5 minutes ago)</p>
// Update relative text every minute — silently (no live region, SC 2.2.2)
const rtf = new Intl.RelativeTimeFormat(navigator.language, { numeric: 'auto' }); // "yesterday", not "1 day ago"
function refreshTimes() {
  for (const el of document.querySelectorAll('time[data-relative]')) {
    const t = new Date(el.dateTime);
    const mins = Math.round((t - Date.now()) / 60000);
    const days = Math.round(mins / 1440);
    el.textContent = Math.abs(days) >= 7
      ? t.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric' }) // switch to absolute
      : Math.abs(mins) < 60 ? rtf.format(mins, 'minute')
      : Math.abs(mins) < 1440 ? rtf.format(Math.round(mins / 60), 'hour')
      : rtf.format(days, 'day');
  }
}
setInterval(refreshTimes, 60_000);

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Event Expected announcement AT deviations
Arrow onto the cell “5 minutes ago” then (after a pause) “2 October 2026 at 10:42 CEST” Descriptions read per reader verbosity
Timer updates text Nothing Text read the next time the user reaches it
Copy the timestamp Relative text copied Offer a copy of the absolute time in a menu if needed
Time older than a week “24 Sept 2026” —
What each technique exposes Matrix of techniques — title attribute, aria-describedby with hidden text, both visible, and a toggletip — against screen reader access, keyboard access, touch access and copyability. What each technique exposesScreen readerKeyboardTouchCopyabletitle attribute onlyRarelyNoNoNoaria-describedbyYesVia reader onlyVia reader onlyNoBoth visibleYesYesYesYesToggletipYesYesYesYes
Visible text or a description reaches everyone; title alone reaches almost no one.

Integration context

Permalink to "Integration context"

Absolute times need zones when users span regions — see announcing time zones in data tables. Freshness stamps on grids use the same markup in stale and partial data indicators. A toggletip for the absolute time follows the toggletip pattern for column help.

Gotchas

Permalink to "Gotchas"

Sorting by relative text. Always sort on the datetime value. Sorting the displayed text puts “yesterday” after “5 minutes ago” alphabetically.

Reading “10:42”. Screen readers read times according to locale; “10:42” is fine, but “10.42” may be read as a decimal number. Use the locale’s time format from Intl.DateTimeFormat.

Future times. Relative wording must handle the future: “in 3 hours”, not “-3 hours ago”. Intl.RelativeTimeFormat does this.

Framework notes

Permalink to "Framework notes"

In React, a <RelativeTime date={d} /> component can share a single minute-ticking context so a table of 500 timestamps does not run 500 timers. In Angular, an impure pipe re-evaluated on a shared timer works, but mark it carefully for change-detection cost. GitHub’s relative-time web component (@github/relative-time-element) renders a time-like element with accessible defaults and works in any framework.

const now = useContext(MinuteClock);   // one timer for the whole app
return <time dateTime={iso} aria-describedby={absId}>{formatRelative(iso, now)}</time>;

Worked example

Permalink to "Worked example"

An admin console lists 400 user accounts with “Last login” shown as “2 hours ago”, “3 days ago” and so on, with the exact time in a title. An auditor using JAWS needs to find accounts that have not logged in since a specific date and cannot: the absolute values are invisible and the relative ones are not comparable. The fix splits the column. “Last login” now shows absolute dates (“12 Sept 2026, 08:15”) and sorts by them; a small “Active recently” badge marks accounts used in the last 24 hours. In the activity feed on the same page, relative times stay — “5 minutes ago” is the right answer there — with the absolute time as a description.

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Provide a Timestamp component with mode="relative" | "absolute" | "both", a shared clock and built-in absolute descriptions. Data tables should default to absolute; feeds to relative with descriptions. Make the threshold for switching to absolute a documented token.

FAQ

Permalink to "FAQ"
Do screen readers read the datetime attribute?

No. They read the element’s text. Put anything users need to hear in text or in a description.

Is the title attribute ever enough for the absolute time?

No. It is not reliably available to keyboard, touch or screen reader users. Use it at most as a duplicate of information available elsewhere.

Should relative times update live?

Yes, silently. Users expect “5 minutes ago” to stay true, but they do not want to hear it change.

How precise should relative times be?

Minutes for the first hour, hours for the first day, days for the first week — then switch to dates. “47 seconds ago” is rarely useful.

What about time stamps in screen reader-friendly exports?

Export the absolute ISO value or a locale-formatted absolute time, never the relative text.

Permalink to "Related"

← Back to Accessible Date & Time Data