Accessible Date & Time Data

Permalink to "Accessible Date & Time Data"

Almost every data interface is full of time: created and updated stamps, due dates, durations, SLA countdowns, schedules, timelines. Time data is deceptively hard to present accessibly. The compact forms that make dense tables readable — “5m ago”, “01:23:45”, “CET”, a coloured bar across a calendar — are exactly the forms that screen readers mispronounce, that keyboard users cannot expand, and that people outside the author’s time zone misread. And the components that collect dates — date pickers, range selectors, calendars — are among the most frequently inaccessible widgets on the web.

This topic covers both sides: presenting time data so it is heard and understood correctly, and collecting it with components that work from the keyboard and with assistive technology. The users most affected are screen reader users (pronunciation, missing absolute times, unstructured calendars), keyboard users (calendar-only pickers, drag-only schedules), users in other time zones (ambiguous times, which is everyone at some point) and users with cognitive disabilities, for whom relative times that drift and abbreviations that need decoding add real effort. The failure this topic prevents is time information that is technically present but unusable — a time without a zone, a duration read as a clock time, a calendar that reads as a pile of titles.

This topic belongs to core ARIA & keyboard navigation for data UIs.

WCAG criteria in scope

Permalink to "WCAG criteria in scope"
Criterion Level Relevance to date and time data
1.3.1 Info and Relationships A Absolute times, zones and event times programmatically available
1.3.2 Meaningful Sequence A Calendar DOM in chronological order
1.4.1 Use of Color A Event categories and overdue states in text
1.4.13 Content on Hover or Focus AA Tooltips with absolute times are dismissible and persistent
2.1.1 Keyboard A Date pickers and calendars fully keyboard operable
2.2.2 Pause, Stop, Hide A Ticking relative times and countdowns update silently
2.5.7 Dragging Movements AA Event move and resize without dragging
3.3.2 Labels or Instructions A Date formats shown for typed entry

Prerequisites

Permalink to "Prerequisites"
Time data across a data product Hierarchy: presentation (timestamps, zones, durations) and collection (typed entry, date picker grid, calendar and timeline views), each with its key requirement. Time data across a data productTime datadates, times, durations, schedulesTimestampstime element; absolute available as textTime zonesonce per column, in the headerDurationslong-form text for assistive technologyTyped entryeditable field with a format hintDate picker gridarrows, Page Up and Down, full day namesCalendars and timelinesstructure, names, agenda alternative
Presentation is about pronunciation and precision; collection is about keyboard operation and alternatives.

ARIA & HTML spec reference

Permalink to "ARIA & HTML spec reference"
Element / attribute Valid values When to apply Common misuse
time datetime ISO 8601 date, time or duration Every rendered date, time or duration Expecting readers to speak the attribute
aria-describedby ID of absolute time text Relative timestamps title attribute only
abbr Expansion in title Zone abbreviations in headers Relying on title being read
role="grid" — Date picker month, interactive month views Table of plain numbers
aria-selected true Selected date in a picker Colour only
aria-current="date" — Today in a picker or calendar Bold text only
aria-disabled true Unavailable dates Removing them from navigation
input inputmode="numeric" — Typed date entry Read-only input that opens a popup

Step-by-step implementation

Permalink to "Step-by-step implementation"

Step 1 — Mark up every time (SC 1.3.1)

Permalink to "Step 1 — Mark up every time (SC 1.3.1)"
<time datetime="2026-10-02T10:42:00+02:00">10:42</time>

See the time element and relative timestamps.

Step 2 — Absolute behind relative (SC 1.3.1, 1.4.13)

Permalink to "Step 2 — Absolute behind relative (SC 1.3.1, 1.4.13)"
<time datetime="…" aria-describedby="abs-1">5 minutes ago</time><span id="abs-1" hidden>2 October 2026 at 10:42</span>

Step 3 — Zones in headers (SC 1.3.1, 2.4.6)

Permalink to "Step 3 — Zones in headers (SC 1.3.1, 2.4.6)"
<th scope="col">Opened (your time, Central European Summer Time)</th>

See announcing time zones in data tables.

Step 4 — Durations with full units

Permalink to "Step 4 — Durations with full units"
<time datetime="PT1H23M"><span aria-hidden="true">1h 23m</span><span class="visually-hidden">1 hour 23 minutes</span></time>

See formatting durations for screen readers.

Step 5 — Typed entry first, calendar second (SC 3.3.2, 2.1.1)

Permalink to "Step 5 — Typed entry first, calendar second (SC 3.3.2, 2.1.1)"
<input id="due" aria-describedby="due-hint"><span id="due-hint">Format: YYYY-MM-DD</span>

See the date picker grid keyboard pattern.

Step 6 — Structured calendars with an agenda (SC 1.3.1, 2.5.7)

Permalink to "Step 6 — Structured calendars with an agenda (SC 1.3.1, 2.5.7)"
<li><a href="/events/41">Design review, 10:00 to 11:00, internal</a></li>

See accessible calendar and timeline views.

Common time formats and how they fail Matrix of formats — relative text, digital duration, zone abbreviation, coloured calendar bar, calendar-only picker — against the users they fail and the fix. Common time formats and how they failFails forFix"5m ago" with titleKeyboard, touch, ATAbsolute time as text or description"01:23:45" durationScreen readers (read as clock)Long-form units"IST" in cellsEveryone outside one regionZone in header, long nameColoured calendar barScreen readers, colour-blind usersEvent name with time and categoryCalendar-only pickerKeyboard and AT usersTyped entry with format hint
Every compact form needs a text equivalent or an alternative route.

Keyboard interaction contract

Permalink to "Keyboard interaction contract"
Context Key Action Expected AT announcement Failure indicator
Date field Typing Enter date Characters echoed Field read-only
Date field Calendar button Open picker “Choose date, dialog, October 2026…” Opens on focus
Picker Arrows Day / week “Saturday, 3 October 2026” “3” only
Picker Page Up / Down Month New month and day Silent month change
Picker Enter / Escape Choose / cancel; focus to field Field with value Focus lost
Month view Enter on day Into event list Event name with time Titles only
Event Edit command Edit time without drag Dialog with start and end Drag only

Screen reader compatibility matrix

Permalink to "Screen reader compatibility matrix"
AT Relative time + description Zone abbreviation Digital duration Picker day names
NVDA Description after pause abbr title not read by default Clock-like Full names if provided
JAWS Verbosity dependent Setting dependent Clock-like Full names if provided
VoiceOver Description after pause Not read Varies Full names if provided
TalkBack Inconsistent descriptions Not read Clock-like Full names if provided
Narrator Description read Not read Clock-like Full names if provided

Edge cases & failure modes

Permalink to "Edge cases & failure modes"

1. Sorting by displayed text

Permalink to "1. Sorting by displayed text"

Diagnosis: “yesterday” sorts after “5 minutes ago”. Fix: sort by the underlying value.

2. Ticking text in a live region

Permalink to "2. Ticking text in a live region"

Diagnosis: “4 minutes ago… 5 minutes ago” announced every minute. Fix: update silently.

3. DST-wrong zone names

Permalink to "3. DST-wrong zone names"

Diagnosis: “CET” shown in summer. Fix: derive names from the displayed date with Intl.

4. Picker that skips disabled dates

Permalink to "4. Picker that skips disabled dates"

Diagnosis: arrow keys jump over unavailable days unpredictably. Fix: keep them focusable with aria-disabled and say “unavailable”.

5. Calendar read as a jumble

Permalink to "5. Calendar read as a jumble"

Diagnosis: absolutely positioned events in arbitrary DOM order. Fix: chronological DOM inside day containers, and an agenda view.

The time element and relative timestamps

Permalink to "The time element and relative timestamps"

Relative times are friendly; absolute times are precise. Use both: relative text, absolute time as text or description, silent updates and absolute dates beyond a week. See the time element and relative timestamps.

new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' }).format(-1, 'day'); // "yesterday"

Announcing time zones in data tables

Permalink to "Announcing time zones in data tables"

One zone per column, stated in the header with a long name; per-record zones in their own column with city names; formatting from Intl so daylight saving is right. See announcing time zones in data tables.

new Intl.DateTimeFormat(undefined, { timeZone: 'Asia/Singapore', timeZoneName: 'long' });

Date picker grid keyboard pattern

Permalink to "Date picker grid keyboard pattern"

A dialog with a month heading and a grid of fully named day buttons; arrows, Home, End and Page keys; typed entry always available. See the date picker grid keyboard pattern.

<button tabindex="0" aria-label="Friday, 2 October 2026">2</button>

Formatting durations for screen readers

Permalink to "Formatting durations for screen readers"

Compact visual forms with long-form text for assistive technology, ISO durations for machines, header units for single-unit columns. See formatting durations for screen readers.

new Intl.DurationFormat(undefined, { style: 'long' }).format({ hours: 1, minutes: 23 });

Accessible calendar and timeline views

Permalink to "Accessible calendar and timeline views"

Structure under the visuals, events named with time and category, keyboard movement by day and period, non-drag editing and an agenda alternative. See accessible calendar and timeline views.

<td role="gridcell" aria-label="Friday 2 October, 3 events">…</td>

Cross-cutting concerns

Permalink to "Cross-cutting concerns"

Locale. Date order (day-month or month-day), week start, 12- or 24-hour clocks and decimal separators all vary. Use Intl everywhere, and in typed inputs either follow the locale’s format or use ISO with a visible hint.

Consistency. A product that shows “2 Oct” in one table and “10/2” in another forces users to re-decode dates constantly. Choose formats per context in the design system and use them everywhere.

Exports. Exports should carry absolute, zone-qualified values, never relative text — see accessible CSV and Excel exports.

Filters. Date range filters must interpret dates in the zone the user sees, or results will be off by a day around midnight. See accessible date range filters.

Worked example: an incident timeline

Permalink to "Worked example: an incident timeline"

An operations team reviews incidents in a timeline view: a horizontal axis of time with coloured bars for alerts, deploys and outages. An on-call engineer who uses NVDA could not use it at all. The redesign keeps the visual timeline and adds, beneath it, the same events as a table ordered by time, with columns “Start (UTC)”, “End (UTC)”, “Duration”, “Type” and “Summary”. Durations read as “23 minutes”; types are words, not colours; the table header says “UTC” once. In the visual timeline, each bar became a focusable element named “Outage, 14:02 to 14:25 UTC, 23 minutes, checkout API”, and arrow keys move between events in time order. The engineer now reviews incidents from the table and uses the timeline’s focusable bars when discussing them with sighted colleagues on a call.

Who is affected, and how

Permalink to "Who is affected, and how"
User group Typical failure Fix
Screen reader users Durations read as clock times; calendars as jumbles Long-form text; structure; agenda view
Keyboard users Calendar-only pickers; drag-only scheduling Typed entry; edit dialogs
Users in other zones Ambiguous times Zones in headers; viewer’s zone
Users with cognitive disabilities Drifting relative times; abbreviations Absolute dates beyond a week; expansions
Colour-blind users Event categories by colour Categories in words

How a timestamp travels through the stack

Permalink to "How a timestamp travels through the stack"

A single value — an invoice’s due date — passes through several layers before a user hears it, and each layer can lose accessibility:

From stored value to spoken text Chain: a stored UTC instant is converted to the viewer's zone, formatted by Intl for the locale, rendered in a time element with a datetime attribute, and read by a screen reader as text with the zone known from the column header. From stored value to spoken textStored value2026-10-02T08:42Z,UTC instantZoneviewer's zone,Europe/LisbonIntl format"2 Oct 2026, 09:42"for the localeMarkuptime element withdatetime and offsetconvertformatrenderHeard"2 October 2026,09:42" + zone fromheader
Most bugs happen at the conversion and formatting steps.

Keep conversion and formatting in one shared utility, so that tables, exports, filters and charts all agree. When they disagree, users see one date in the grid and another in the export — a confusing bug for anyone, and very hard to diagnose for a screen reader user.

Measuring date and time quality

Permalink to "Measuring date and time quality"

Audit a product’s time data with three quick checks: search the codebase for title= on time-like elements (each is a candidate for an inaccessible absolute time); list every date picker and confirm it accepts typed input; and listen to a table of durations with a screen reader to catch clock-style readings. Fixing those three classes of issue removes most of the problems this topic describes.

Design system integration

Permalink to "Design system integration"

Provide Timestamp, Duration, DateField (with optional calendar), DateRangeField and calendar views as components that format with Intl, render accessible text alongside compact forms, and expose zone and precision as configuration. Column types for tables — datetime, date, duration — should drive formatting, header units and sorting together. Document formats per context (tables, feeds, headers) so every product uses the same ones.

Testing checklist

Permalink to "Testing checklist"

Automated

Permalink to "Automated"

Keyboard

Permalink to "Keyboard"

Screen reader

Permalink to "Screen reader"

FAQ

Permalink to "FAQ"
Should I always show absolute times?

In tables and anywhere users compare or audit, yes. In feeds, relative is fine as long as absolute is available on demand.

Are native date inputs accessible?

They are improving, and they provide typed segments, but behaviour differs between browsers. Test them with your target screen readers before relying on them.

How do screen readers read ISO dates like 2026-10-02?

Usually as “2026 dash 10 dash 02” or similar. It is unambiguous but not pleasant; for display, use locale formats with month names in dense contexts where clarity matters.

Do I need an agenda view for every calendar?

For any calendar users rely on to find or manage events, yes. It is the most accessible view and often the fastest for everyone.

How do I handle dates without a year in tables?

Only omit the year when every date in the column is in the current year, and say so in the header (“Due (2026)”). Otherwise include it.

Should countdown timers be announced?

Not continuously. Announce thresholds that require action — “5 minutes until the session ends” — and provide a way to extend, as WCAG 2.2.1 requires for session timeouts.

Where should I start fixing time data in an existing product?

Start with date pickers, because they block tasks outright when inaccessible. Then fix durations and relative times in the most-used tables, and finally add agenda alternatives to calendars. Each step is independent and delivers value on its own.

Permalink to "Related"

← Back to Core ARIA & Keyboard Navigation for Data UIs