RelativeTime
العربيةA hand-built "3 days ago" is English-only and loses the exact timestamp, which a screen reader user can never hover to recover.
What most apps ship
3 days ago
`${days} days ago`Live, localised relative time ("3 days ago") with the exact timestamp always available.
This is the exact fixture the conformance suite renders in CI. Switch the language to see the component mirror and reformat.
A hand-built "3 days ago" is English-only and loses the exact timestamp, which a screen reader user can never hover to recover.
What most apps ship
3 days ago
`${days} days ago`npx shadcn@latest add https://kata-ui-rho.vercel.app/r/relative-time.jsonCopies the source into your project. Pulls in 3 primitives: format, locale, use-locale.
"use client";
import { useEffect, useState } from "react";
import { formatRelative, dateTimeFormat } from "../lib/format";
import { useLocale } from "../lib/use-locale";
export interface RelativeTimeProps {
value: Date | number;
/** Re-render interval in ms, so "in 1 minute" becomes "now" on its own. */
updateInterval?: number;
className?: string;
}
/**
* "3 days ago", live and in the reader's own language and calendar. The exact
* timestamp is always available too — on hover for a mouse, and permanently
* for assistive tech via `title`, since a screen reader does not hover.
*/
export function RelativeTime({ value, updateInterval = 60_000, className }: RelativeTimeProps) {
const { locale, calendar } = useLocale();
const [, forceUpdate] = useState(0);
useEffect(() => {
const timer = setInterval(() => forceUpdate((n) => n + 1), updateInterval);
return () => clearInterval(timer);
}, [updateInterval]);
const date = new Date(value);
const exact = dateTimeFormat(locale, { dateStyle: "full", timeStyle: "short", calendar }).format(
date,
);
return (
<time dateTime={date.toISOString()} title={exact} className={className} suppressHydrationWarning>
{formatRelative(date, locale)}
</time>
);
}