react-cal-kit
v0.1.2
Published
Zero-dependency React calendar component library with Month, TimeGrid, List, DayGrid, MultiMonth and Timeline views, event CRUD and drag & drop. Google Calendar-style theme.
Maintainers
Readme
react-cal-kit
Zero-dependency React calendar component. Google Calendar–styled, CSS Modules, full TypeScript types.
Status: All 7 views, multi-day bars, recurring events, and a 42-test Vitest+RTL suite are in. Published to npm — see Roadmap for what's left (per-occurrence recurrence overrides, a11y pass).
Install
npm install react-cal-kitUsage
import { Calendar } from "react-cal-kit";
import "react-cal-kit/styles.css";
const events = [
{ id: "1", title: "Standup", start: "2026-09-03T09:00:00", end: "2026-09-03T09:15:00" },
{ id: "2", title: "Conference", start: "2026-09-10", end: "2026-09-13", allDay: true, color: "#0b8043" },
];
function App() {
return (
<Calendar
events={events}
onEventCreate={(e) => console.log("create", e)}
onEventUpdate={(e) => console.log("update", e)}
onEventDelete={(id) => console.log("delete", id)}
/>
);
}Why this exists
Built to avoid vendor lock-in and per-seat/commercial licensing on calendar UI. No runtime dependencies — dates are handled with native Date/Intl, so there's no date-fns/dayjs/moment tax on your bundle.
Views
Pass any subset via the views prop to control what shows in the switcher — the default is all seven:
month · timeGridWeek · timeGridDay · dayGridWeek · list · multiMonth · timeline
timeline groups events by resourceId into the rows given via the resources prop; without resources, all events render in a single "Events" row.
API
<Calendar />
| Prop | Type | Notes |
|---|---|---|
| events | CalendarEvent[] | required |
| initialView / view | CalendarViewType | uncontrolled/controlled |
| initialDate / date | Date | uncontrolled/controlled |
| views | CalendarViewType[] | which views show in the switcher |
| firstDayOfWeek | 0 \| 1 | Sunday or Monday |
| editable | boolean | enables drag & drop |
| selectable | boolean | enables click-to-create |
| locale | string | passed to Intl |
| onEventCreate/Update/Delete | callbacks | fired by the built-in quick-add popover and drag/drop |
| onEventDrop | callback | fired on reschedule via drag & drop, before onEventUpdate |
| onEventClick | callback | if provided, replaces the built-in edit popover — you own the UI |
| renderEvent | (event) => ReactNode | custom chip content |
CalendarEvent: { id, title, start, end, allDay?, color?, resourceId?, editable?, extendedProps?, recurrence? }. start/end accept ISO strings or Date.
Recurring events
Set recurrence on an event for a simple repeat rule ("RRULE-lite" — daily/weekly/monthly/yearly, not full RFC 5545):
{
id: "standup",
title: "Standup",
start: "2026-09-03T09:00:00",
end: "2026-09-03T09:15:00",
recurrence: { freq: "daily", count: 20 }, // or: until, interval, exDates
}Occurrences are expanded on the fly for whatever range is on screen (expandRecurringEvents, also exported for host apps that need it directly). Editing or dragging an occurrence currently acts on the whole series — a title edit renames the series, a drag/resize shifts every occurrence by the same delta. There's no per-occurrence override yet (see Roadmap).
Theming
One theme, tuned to look like Google Calendar, exposed as CSS custom properties on .rck-root (see src/styles/theme.css). Override any of --rck-accent, --rck-today-bg, --rck-border, etc. from your own stylesheet.
Development
npm install
npm run build # tsup -> dist/ (ESM + CJS + .d.ts + bundled CSS)
npm run typecheck
npm run test # vitest, 42 tests: utils (date/layout/recurrence/multi-day) + Calendar CRUD flows via RTL
npm run test:watchCI (.github/workflows/ci.yml) runs typecheck + test + build on every push and PR.
Releasing
Version bumps and the changelog are managed by Changesets:
npx changeset # after a change worth releasing, describe it + bump type (patch/minor/major)
git add .changeset && git commit -m "changeset"Push to main. .github/workflows/release.yml (using changesets/action) then:
- Opens/updates a "Version Packages" PR that applies the pending changesets to
package.json/CHANGELOG. - Once that PR is merged, the same workflow builds and publishes to npm.
Requires an NPM_TOKEN secret (an npm automation token with publish rights) in the repo settings. First publish has to be done once manually (npm publish) if the package name isn't claimed yet.
Roadmap
- [x] Month
- [x] TimeGrid Week / Day (hour grid, overlap layout, drag to move, handle to resize, now-indicator)
- [x] List (grouped by day, quick add, empty-state)
- [x] DayGrid (single-row week grid, no time-of-day)
- [x] MultiMonth (year-at-a-glance, click a day to jump into Month)
- [x] Timeline (resource lanes, drag horizontally to reschedule, drag vertically to reassign resource, edge-handle resize)
- [x] True multi-day event bars in Month/DayGrid (single spanning bar with lane stacking, not repeated per day cell)
- [x] Recurring events (RRULE-lite: daily/weekly/monthly/yearly, interval, count, until, exDates)
- [x] Tests (Vitest + React Testing Library)
- [ ] Per-occurrence recurrence overrides/exceptions (currently series-level edits only)
- [ ] Weekly-by-specific-weekdays recurrence (e.g. Mon/Wed/Fri)
- [ ] Keyboard navigation / a11y pass
- [x] Published to npm as
react-cal-kit(currently 0.1.x — v1.0.0 pending broader API stabilization)
License
MIT
