Text
RelativeTime
How long ago (or how soon) something happens, in the reader's language: "3 days ago", "yesterday", "in 5 minutes", "now", kept current while it shows. It is a <time> with the exact instant, and its title gives the full local date and time. The server writes the UTC date (in en-US unless locale is set) and hydration repeats it, so the markup matches; the browser then shows the relative time in the reader's language. A calendar date with no time ("2026-06-01") counts whole days from the reader's own today ("tomorrow", "in 3 days"), and its title and <time> carry that day, never moved into a time zone.
In Spoonjoy
Spoonjoy, a recipe app, is built with Ouro HX (how).
See it live, no sign-in needed: A recipe
In its source: app/components/recipe/SpoonsStrip.tsx · app/components/users/FellowChefList.tsx
Install
Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):
npx shadcn@latest init --base base --preset nova --yes --no-monoreponpx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):
npx shadcn@latest add ourostack/ouro-ui/relative-time#v1.2.13Or, with the @ouro namespace set up:
npx shadcn@latest add @ouro/ouro-base @ouro/relative-timeIts tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):
npx shadcn@latest add ourostack/ouro-ui/relative-time#v1.2.13 ourostack/ouro-ui/relative-time-tests#v1.2.13import { RelativeTime } from "@/components/ouro/relative-time/relative-time";Paths use shadcn's default @/ alias; the CLI rewrites them to yours.
Example
<RelativeTime value={comment.createdAt} />Use instead when
- Use
LocalDateinstead where the date itself matters, such as a due date.
Props
Type: RelativeTimeProps.
className- Type:
string - Layout only. Appearance classes warn in development.
locale- Type:
Intl.LocalesArgument - Default: the reader's (en-US in the server's text, until the browser takes over)
- The language and region to write it in.
numeric- Type:
"auto" | "always" - Default:
"auto" autosays "yesterday" and "now";alwayssays "1 day ago" and "in 0 seconds".ref- Type:
Ref<HTMLTimeElement> - Reaches the rendered element.
value(required)- Type:
Date | string | number - The instant: a
Date, an ISO string or a timestamp in milliseconds. A calendar date with no time ("2026-06-01", or"2026-06"for a month) counts whole days (or months) in the reader's own calendar and is never moved into a time zone.
Native attributes
Also accepts the attributes in React's HTMLAttributes and TimeHTMLAttributes (id, aria-*, event handlers), passed to the rendered element, except those named on this page.
Don't use
These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.
date: Not a prop. The instant isvalue:<RelativeTime value={comment.createdAt} />.now: Not a prop. The time updates itself; nothing to pass.
className is for layout only
Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: RelativeTime merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes
Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.
Alignment classes (text-center) warn too: set alignment on a parent element.
Claim sources
- layout-classes: test:registry/ouro/components/ouro/relative-time/relative-time.test.tsx::RelativeTime > forwards a ref and <time> attributes, and lets app layout classes win
verify:testExists(registry/ouro/components/ouro/relative-time/relative-time.test.tsx::RelativeTime > forwards a ref and <time> attributes, and lets app layout classes win)