A React 19 calendar built on the Temporal API, with views you copy into your app and own.
Documentation · Quick start · Live demo · Releases
Time handles dates, time zones, navigation, calendar state, fast event lookups, and saving changes.
Your events stay in the shape your app already uses, and Time reads them through a small adapter.
The screenshot is the live demo, a Google Calendar-style
app built from the same views. Its source is in apps/demo.
Note
The packages are on npm as a release candidate for 1.0.0. The API can still change before 1.0.0 if the release candidate turns up problems.
- Temporal, not
Date. Timed events useTemporal.Instant, all-day events useTemporal.PlainDate, and floating events useTemporal.PlainDateTime. - Time zones and daylight saving time. Time lays out days that are 23 or 25 hours long, and hours that a clock change skips or repeats.
- Your event shape. An adapter tells Time how to read an ID, a title and a time range from your records. TypeScript keeps your record and ID types.
- Views you own. Week, day, month, year, agenda, resource columns and resource timeline are shadcn/ui source files. The shadcn CLI copies them into your app, in Tailwind CSS or StyleX.
- Editing. People drag, resize and create events with a mouse, a pen or touch. Each edit arrives as a change for you to save. It shows as pending while it saves and rolls back if saving fails.
- Controlled or uncontrolled state. The calendar or your app can own the visible date, the view, the time zone, the selection and the focus.
- Server rendering. During server rendering, Time doesn't read the clock, the host time zone or
window, so the server and the browser render the same markup from the same props. - Recurrence and iCalendar. Separate packages expand RRULE series inside the visible range and parse ICS feeds.
Comparison sets Time beside FullCalendar and react-big-calendar, including where they're ahead.
pnpm add @moltenship/calendar react react-domTime needs:
- React 19.
- A runtime with
Temporal. Node.js 26 and later include it. In a browser without it, load a polyfill before the calendar. Time never bundles one. - TypeScript 6 or later with
"lib": ["DOM", "DOM.Iterable", "ESNext"].
Installation covers the polyfill and the TypeScript setup.
The smallest calendar, with a hand-written view:
import {
createCalendar,
defineCalendarView,
defineEventAdapter,
plainDateInterval,
} from "@moltenship/calendar";
interface Meeting {
id: string;
title: string;
start: Temporal.Instant;
end: Temporal.Instant;
}
const eventAdapter = defineEventAdapter<Meeting>()({
getId: (meeting) => meeting.id,
getTitle: (meeting) => meeting.title,
getInterval: (meeting) => ({ kind: "timed", start: meeting.start, end: meeting.end }),
getResourceIds: () => [],
});
// A minimal view: the meetings on the visible day.
const dayView = defineCalendarView({
name: "day",
strategy: {
getRange: (date) => plainDateInterval(date, date.add({ days: 1 })),
navigate: (date, delta) => date.add({ days: delta }),
getTitle: (range, { locale }) => range.start.toLocaleString(locale, { dateStyle: "full" }),
project: ({ snapshot, instantRange }) => snapshot.queryTimed(instantRange),
},
Renderer: ({ projection }) => (
<ul>
{projection.map((meeting) => (
<li key={meeting.id}>{meeting.title}</li>
))}
</ul>
),
});
const Calendar = createCalendar<Meeting>()({ eventAdapter, views: [dayView] });
export function MeetingCalendar({ meetings }: { meetings: readonly Meeting[] }) {
return (
<Calendar.Root
events={meetings}
defaultAnchorDate={Temporal.PlainDate.from("2026-10-08")}
defaultTimeZone="Europe/Berlin"
locale="en-US"
weekRules={{ firstDay: 1, minimalDays: 4, weekend: [6, 7] }}
>
<Calendar.PreviousTrigger>Previous</Calendar.PreviousTrigger>
<Calendar.Title />
<Calendar.NextTrigger>Next</Calendar.NextTrigger>
<Calendar.ActiveView />
</Calendar.Root>
);
}The styled views aren't in the npm package. Add the week and day, month, and agenda views with the shadcn CLI:
npx shadcn@latest add \
https://time.molten.sh/r/time-grid-view.json \
https://time.molten.sh/r/month-view.json \
https://time.molten.sh/r/list-view.jsonThe files land in components/calendar/, along with the theme, the toolbar and the view switcher.
The Quick start wires them into createCalendar.
Most apps import @moltenship/calendar alone. It re-exports the React, pointer-interaction, core
and Temporal packages.
| Package | What it does |
|---|---|
@moltenship/calendar |
The package you install: React components and hooks, the event engine, Temporal helpers and pointer interactions. |
@moltenship/calendar-recurrence |
RRULE expansion inside a range, exceptions and series edits. |
@moltenship/ics |
Typed iCalendar (RFC 5545) parsing into Temporal values, with Standard Schema support. |
@moltenship/calendar-dnd-kit |
A dnd-kit adapter: drag your own items into the calendar and events out. |
@moltenship/calendar-testing |
Test helpers: a deterministic environment, builders and fixtures, a render harness, and keyboard and pointer drivers. |
@moltenship/calendar-react |
The headless React components and hooks. |
@moltenship/calendar-dnd |
Pointer drag, resize and create interactions for views. |
@moltenship/calendar-core |
The framework-independent engine: event data, projection, layout and interactions. |
@moltenship/calendar-temporal |
Framework-independent Temporal utilities. |
The docs are at time.molten.sh. Good places to start:
To work on the docs, run vp run dev and edit the MDX in
apps/showcase/content/docs. Start the demo with
vp run demo#dev.
The repository uses the Vite+ toolchain (vp) and Node.js 26.
vp install # install dependencies
vp check # format, lint, and type-check
vp test # run the tests
vp run ready # everything CI runs
vp run ready:full # the release gatearchitecture.mdis the design the project is building toward.docs/adrrecords individual design decisions.docs/internalhas contributor notes: quality gates, package layout and releasing.- Planned work is tracked in GitHub issues.
- Each release's notes are on GitHub Releases;
CHANGELOG.mdhas1.0.0-rc.1's.
MIT. @moltenship/ics also bundles Unicode CLDR data under the Unicode License v3, so
it's MIT AND Unicode-3.0; see its
THIRD-PARTY-NOTICES.md.