One date, time or duration as relative, calendar, absolute or duration text, on a native time element.
<tp-time>
Time
Default density
Compact density
Restart from the initial state
Show the copyable source
Maya Chen merged #482
Jonas Weber deployed to production
Priya Natarajan opened #479
Maya Chen merged #482
Jonas Weber deployed to production
Priya Natarajan opened #479
<ul id="time-hero" style="display:grid;gap:var(--tp-space-3);max-inline-size:24rem;margin:0 auto;padding:0;list-style:none;font-size:var(--tp-text-sm)">
<li style="display:flex;justify-content:space-between;gap:var(--tp-space-4)">
<span><strong>Maya Chen</strong> merged #482</span>
<tp-time data-offset="-45" style="color:var(--tp-muted-foreground)"></tp-time>
</li>
<li style="display:flex;justify-content:space-between;gap:var(--tp-space-4)">
<span><strong>Jonas Weber</strong> deployed to production</span>
<tp-time data-offset="-1500" style="color:var(--tp-muted-foreground)"></tp-time>
</li>
<li style="display:flex;justify-content:space-between;gap:var(--tp-space-4)">
<span><strong>Priya Natarajan</strong> opened #479</span>
<tp-time data-offset="-97200" style="color:var(--tp-muted-foreground)"></tp-time>
</li>
</ul>
<script type="module">
// Demo data: instants relative to the moment the page loads.
for (const time of document.querySelectorAll('#time-hero tp-time')) {
time.datetime = new Date(Date.now() + Number(time.dataset.offset) * 1000);
}
</script>
Usage
Set datetime to an ISO string, an epoch number or a Date; without it the element reads its own text, so server-rendered dates upgrade in place. Relative text refreshes on one shared timer when it can next change, and focusing or hovering a value shows the full date and time.
datetime accepts a Date, an epoch number, text, or a Temporal-like object with epochMilliseconds or an ISO toString(). The <time> element always carries a valid machine-readable datetime at that precision. Time does not store values or synchronize clocks.
Absolute presentations do not refresh. The timer stops while the page is hidden and every element refreshes when it becomes visible, after a languagechange, or when a lang attribute in the document changes. Changes to lang inside other shadow roots apply at the next refresh. Updates are never announced through a live region.
Message’s timestamp renders a Time with defaults; use the Message header slot with your own tp-time for other options. Use Time inside List item footers, Table cells, Card or Alert text, Preview card content and Tooltip triggers wherever a date is displayed. For strings outside the DOM, such as a Toast description, use the exported resolveTime and formatTime.
Modes
auto (the default) is relative within 30 days and absolute beyond. calendar says “Yesterday at 16:20”; duration shows a length of time.
Modes
Default density
Compact density
Restart from the initial state
Show the copyable source
Write yyyy-MM-dd, not Moment-style YYYY-MM-DD: unsupported letters render literally and raise a diagnostic instead of silently formatting a different year.
pattern uses Unicode date-field symbols, localized through Intl: y, yy, yyyy; M, MM, MMM, MMMM, MMMMM (L is equivalent); d, dd; E–EEE, EEEE, EEEEE; a; h, hh, H, HH, K, k; m, mm; s, ss; S–SSS; z, zzzz; X–XXX, x–xxx. Quote literal text: "d MMM 'at' HH:mm", with '' for an apostrophe. Week-year Y, day-of-year D and other unsupported letters render literally and emit a tp-diagnostic.
Dates and time zones
A date-only value stays on its calendar day in every time zone and compares by days. Instants format in the browser’s zone unless time-zone names one, and hour-cycle forces 12- or 24-hour clocks.
Dates and zones
Default density
Compact density
Restart from the initial state
Show the copyable source
Invoice due Standup: New York · Berlin
Invoice due Standup: New York · Berlin
<div style="display:grid;gap:var(--tp-space-2);justify-items:center;font-size:var(--tp-text-sm)">
<span>Invoice due <tp-time mode="absolute" preset="date-medium" datetime="2026-11-01"></tp-time></span>
<span>Standup: <tp-time mode="absolute" preset="time" datetime="2026-10-12T09:30:00Z" time-zone="America/New_York"></tp-time> New York · <tp-time mode="absolute" preset="time" datetime="2026-10-12T09:30:00Z" time-zone="Europe/Berlin" hour-cycle="h23"></tp-time> Berlin</span>
</div>
Relative date-only values compare by calendar days too, which suits due dates in a task list.
Due dates
Default density
Compact density
Restart from the initial state
Show the copyable source
mode="calendar" names nearby days, such as “Today at 09:12” or “Last Friday at 16:40”, and falls back to an absolute date beyond a week. Month and weekday names come from the locale; the surrounding phrases come from the messages property, with {time}, {weekday} and {date} placeholders, so you can translate or reword them.
Calendar
Default density
Compact density
Restart from the initial state
Show the copyable source
Last login
Invoice sent
Plan changed
Último acceso
Last login
Invoice sent
Plan changed
Último acceso
<dl id="time-calendar" style="display:grid;grid-template-columns:auto auto;gap:var(--tp-space-2) var(--tp-space-6);margin:0;font-size:var(--tp-text-sm)">
<dt style="color:var(--tp-muted-foreground)">Last login</dt><dd style="margin:0"><tp-time mode="calendar" data-offset="-3600"></tp-time></dd>
<dt style="color:var(--tp-muted-foreground)">Invoice sent</dt><dd style="margin:0"><tp-time mode="calendar" data-offset="-90000"></tp-time></dd>
<dt style="color:var(--tp-muted-foreground)">Plan changed</dt><dd style="margin:0"><tp-time mode="calendar" data-offset="-345600"></tp-time></dd>
<dt lang="es" style="color:var(--tp-muted-foreground)">Último acceso</dt><dd lang="es" style="margin:0"><tp-time mode="calendar" data-offset="-3600" data-spanish></tp-time></dd>
</dl>
<script type="module">
for (const time of document.querySelectorAll('#time-calendar tp-time')) {
time.datetime = new Date(Date.now() + Number(time.dataset.offset) * 1000);
}
document.querySelector('#time-calendar [data-spanish]').messages = {
today: 'Hoy a las {time}',
yesterday: 'Ayer a las {time}',
};
</script>
Relative style
relative-style shortens relative text for dense layouts; the long form stays available to assistive technology. numeric="always" replaces phrases like “yesterday” with counts.
Relative text uses Intl.RelativeTimeFormat with one unit. Boundaries are 60 seconds, 60 minutes, 24 hours, 7 days, 30 days and 365 days. rounding="floor" (default) shows “1 hour ago” until two hours have passed; round rounds to the nearest count and promotes to the next unit at a boundary. Distances below now-threshold (default PT10S) or below one precision unit read “now”. With numeric="auto" (default) the locale may say “yesterday” or “last week”.
Short and narrow
Default density
Compact density
Restart from the initial state
Show the copyable source
<div id="time-styles" style="display:flex;gap:var(--tp-space-6);font-size:var(--tp-text-sm)">
<tp-time data-offset="-7200"></tp-time>
<tp-time data-offset="-7200" relative-style="short"></tp-time>
<tp-time data-offset="-7200" relative-style="narrow"></tp-time>
<tp-time data-offset="-86400" numeric="always"></tp-time>
</div>
<script type="module">
for (const time of document.querySelectorAll('#time-styles tp-time')) {
time.datetime = new Date(Date.now() + Number(time.dataset.offset) * 1000);
}
</script>
Other precisions
A value keeps the precision it was written with: a month, a yearless date such as a birthday, an ISO week or a time of day each format as exactly that, never as a full date with invented parts.
Precisions
Default density
Compact density
Restart from the initial state
Show the copyable source
mode="duration" on an instant shows the time until or since it as a ticking length, such as a call timer or a sale countdown. precision sets the smallest unit shown, which also slows the updates. tense="past" shows a slightly future instant, for example from a server clock that runs ahead, as “now” instead of “in 3 seconds”.
Timers
Default density
Compact density
Restart from the initial state
Show the copyable source
In auto mode, threshold (an ISO duration, P30D by default) sets how far from now values stay relative before they switch to absolute text.
Description
The tooltip shows tooltip-pattern (default dd/MM/yy HH:mm) and makes the value focusable. It is skipped when it would repeat the visible text; tooltip="false" removes it and the tab stop.
The default pattern is reduced to the value’s precision: dd/MM/yy for dates, HH:mm for times, MM/yy for months. No description or tab stop is added when it would repeat the visible text, or for durations and weeks. Use tooltipFormatter for full control.
Description
Default density
Compact density
Restart from the initial state
Show the copyable source
Input that cannot be read as a date, time or duration keeps the authored content and exposes data-invalid, so a server-rendered label never turns into a wrong date.
Resolution order:
Date and objects with epochMilliseconds.
Numbers, and text of 9–13 digits optionally prefixed with @: epoch seconds below 100000000000, milliseconds otherwise.
Time-element microsyntaxes: 2026 (year), 2026-10 (month), 2026-10-05 (date), --10-05 or 10-05 (yearless), 2026-W40 (week), 14:30[:05[.123]] (time), 2026-10-05T14:30 or with a space (local date-time), and the same with Z or ±HH:MM (instant).
Durations: PT1H30M, P1DT2H, P1Y2M, or 1h 30m, 3w 2d.
Internet message dates: Mon, 05 Oct 2026 14:30:00 GMT.
The browser’s best-effort parser, marked loose. Set strict to reject it.
A local date-time without an offset is a wall-clock value in the resolved time zone.
Fallback
Default density
Compact density
Restart from the initial state
Show the copyable source
Default density
Compact density
Restart from the initial state
Show the copyable source
The build is green again.
The build is green again.
<div id="time-message"><tp-message author="Ada" data-offset="-120">The build is green again.</tp-message></div>
<script type="module">
/** Assign live datetimes so relative examples stay current. */
export function setupTimeExample(root) {
const now = Date.now();
for (const time of root.querySelectorAll('tp-time[data-offset]'))
time.datetime = new Date(now + Number(time.dataset.offset) * 1000);
for (const time of root.querySelectorAll('tp-time[data-days]')) {
const date = new Date(now + Number(time.dataset.days) * 86_400_000);
time.datetime = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}
for (const message of root.querySelectorAll('tp-message[data-offset]'))
message.timestamp = new Date(now + Number(message.dataset.offset) * 1000);
const calendar = root.querySelector('tp-time[data-messages]');
if (calendar) calendar.messages = { today: 'Hoy a las {time}', yesterday: 'Ayer a las {time}' };
return () => {};
}
setupTimeExample(document.getElementById('time-message'));
</script>
API Reference
Every element also accepts motion-policy.
Attributes
AttributePropertyTypeDefaultDescriptiondatetimedatetimeTimeInputundefinedThe value: a Date, an epoch number, or ISO or duration text; the element's text is read when it is unset.strictstrictbooleanfalseRejects text that only the browser's lenient date parser can read.modemodeTimeMode'auto'How the value is presented: auto is relative within threshold and absolute beyond it.thresholdthresholdstring'P30D'How far from now, as an ISO duration, auto stays relative.presetpresetTimePreset'datetime'A named, locale-aware absolute format.patternpatternstring''An exact absolute layout in Unicode date-field symbols, such as yyyy-MM-dd; quote literal words.relative-stylerelativeStyleTimeStyle'long'The length of relative and duration text; shorter forms keep the long one for assistive technology.numericnumeric'auto' | 'always''auto'always writes counts ("1 day ago") where the locale would say "yesterday".tensetenseTimeTense'auto'Clamps values on the other side of now to "now", such as a server clock running slightly ahead.precisionprecisionTimeUnit'second'The smallest unit relative and duration text shows, which also sets how often it refreshes.roundingroundingTimeRounding'floor'Whether relative counts round down or to the nearest unit.now-thresholdnowThresholdstring'PT10S'How close to now, as an ISO duration, a value reads as "now".localelocalestring''The formatting locale, in place of the nearest lang.time-zonetimeZonestring''The time zone, such as Europe/Berlin, for instants and calendar days; the browser's zone by default.hour-cyclehourCycleTimeHourCycle | ''''Forces a 12- or 24-hour clock in place of the locale's.update-intervalupdateIntervalTimeUpdateInterval'auto'When the text refreshes: auto when it can next change, none never, or every given number of milliseconds.tooltiptooltipbooleantrueShows the full date and time in a tooltip and makes the value focusable; tooltip="false" removes both.tooltip-patterntooltipPatternstring'dd/MM/yy HH:mm'The tooltip's layout in Unicode date-field symbols.
Properties
PropertyTypeDefaultDescriptionformatIntl.DateTimeFormatOptions | undefined—Date and time format options for absolute text, used when there is no pattern.formatter((context: TimeFormatContext) => string) | undefined—Returns the absolute text itself, ahead of pattern, format and preset.nowTimeInputundefinedA fixed reference instant in place of the current time, which stops the refresh.messagesPartial<TimeMessages>{}Calendar and week phrases, such as today: 'Hoy a las {time}'; missing entries keep the defaults.tooltipFormatter((context: TimeFormatContext) => string) | undefined—Returns the tooltip's text itself.valueread-onlyResolvedTime | null—The resolved value, or null when the input cannot be resolved.textread-onlystring—The currently presented text.
Events
EventTypeDescriptiontp-time-updateCustomEvent<TimeUpdateDetail>The presented text changed after the first render; detail holds text, previousText and the resolved value.
Methods
MethodReturnsDescriptionrefreshTime()voidUpdates the text against the current time now, outside the shared refresh.
Slots
SlotDescriptiondefaultThe value as text, read when datetime is unset, so server-rendered dates upgrade in place; text it cannot read is shown unchanged.
CSS parts
PartDescription::part(time)The host, which inherits font and color from its context.::part(time-description)The tooltip with the full date and time.::part(time-value)The native time element: tabular numerals that do not wrap, and the focus ring while a tooltip is available.
Related
Components, widgets and patterns that use this one.