Skip to content

RelativeTime

MD · 1950B gzip budget

Live, localised relative time ("3 days ago") with the exact timestamp always available.

Category
Internationalisation
Budget
md, several states or a live subscription
External runtime
React / React DOM only
axe fixtureSSR rendersource scanbundle budget

Preview

Live fixture
Preview locale

Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.

Why this exists

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.

Formatting shortcut

3 days ago

`${days} days ago`

RelativeTime

relative-time

Install

npx shadcn@latest add https://gear5-ui.vercel.app/r/relative-time.json

Copies the source into your project. Pulls in 3 shared registry items: format, locale, use-locale.

New here? Set up Tailwind and import aliases first →

Source & props

Edit on GitHub ↗

Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.

"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>
  );
}

What CI checks

Quality contract
  • Bundled, minified and gzipped against its tier budget
  • Audited by axe in the state previewed above
  • Rendered through react-dom/server with no browser globals
  • Scanned for network calls, dangerous sinks, and unguarded animation