# Daybook — Event Calendar & Scheduler for React, shadcn/ui & Tailwind (Drag & Drop)

> A full event calendar and scheduler for React and shadcn/ui: month, week, day and agenda views, drag-and-drop to create, move and resize, recurring events, attendees with photos and RSVPs, team calendars, search and shortcuts, Undo everywhere. Light and dark, mobile to desktop.

- Kind: Component (Forms)
- Price: comes with the Pro plan
- License: UpFork Standard License. Use it in unlimited personal and commercial projects. Don't resell or redistribute it on its own.
- Developer: UpFork
- Tags: form, list, dashboard, calendar, event-calendar, scheduler, agenda, drag-and-drop, recurring-events, shadcn, base-ui, nextjs
- npm packages: @base-ui/react, @dnd-kit/core, @tiptap/react, @tiptap/starter-kit, class-variance-authority, cmdk, date-fns, lucide-react, motion, react-day-picker, sonner, zustand
- Published: 2026-10-24
- Updated: 2026-10-24
- Page: https://upfork.dev/products/shadcn-event-calendar-scheduler-react

## How to get it

Install it into a React + Tailwind project with the shadcn CLI:

```bash
npx shadcn@latest add @upfork/shadcn-event-calendar-scheduler-react
```

It installs with the member's personal CLI token (UPFORK_TOKEN), made on their UpFork account page. It comes with UpFork's Pro plan and the plans after it.

## About

A complete calendar app for React and shadcn/ui: month, week, day and agenda views; drag to create, move and resize;
repeating events; attendees with photos and RSVPs; teammates' calendars; search, settings and keyboard shortcuts;
Undo on every change. Light and dark, phone to desktop, keyboard and screen reader friendly.

```tsx
import { Toaster } from "sonner"
import { EventCalendar } from "@/components/calendar/event-calendar"

export default function CalendarPage() {
  return (
    <div className="h-dvh p-4">
      <EventCalendar />
      <Toaster position="bottom-right" closeButton />
    </div>
  )
}
```

Give it a height (it fills its parent and scrolls inside its views). Without `events` it shows the demo calendar,
moved to the current week so it always looks alive.

## Your data

```tsx
<EventCalendar
  events={events}            // CalendarEvent[]
  categories={categories}    // your calendars: { id, name, color: "amber" | "violet" | "rose" | "emerald" | "sky" }
  people={people}            // everyone who can be invited, the signed-in user included
  me="u_42"                  // the signed-in user's id: organizer of new events
  onEventsChange={save}      // after every create, move, resize, edit, delete and undo
/>
```

| Prop | What it does |
| --- | --- |
| `events` | Timed events keep ISO instants (`start`, `end`, exclusive) and the `timeZone` they were entered in; all-day events keep dates (`start`, `end`, both inclusive, `YYYY-MM-DD`). Optional: `description` (basic rich text), `location`, `videoUrl`, `organizerId`, `attendees` (`{ personId, rsvp }`), `reminders` (minutes before), `recurrence`, `exdates`, `kind: "out-of-office"`. |
| `categories` | Defaults to Family, Business, Personal, Holiday and Etc. Each takes one of the five colour recipes. |
| `people`, `me` | Defaults to the demo team. Photos are plain `<img>`; initials show only if one fails to load. |
| `defaultView`, `defaultDate` | Where it opens when the URL and the visitor's last choice don't say. Phones open on Agenda (or Day, if that was their last choice). |
| `defaultTeam` | Teammates whose calendars start switched on. |
| `defaultSettings` | Week start, 12/24 h, weekends, dimming, week numbers, working hours, time zone, density. |
| `syncUrl` | Keeps `?view=week&date=2026-10-15&event=…` in the address bar (default on). |
| `persist` | Remembers the view, filters, sidebar and settings in `localStorage` (default on). |
| `onEventsChange` | Called with the whole list after each change. |

Repeating events: `recurrence: { freq: "daily" | "weekly" | "monthly" | "yearly", interval, byWeekday?, nth?, until?, count? }`.
A series expands only over the range a view shows. Editing, moving or deleting one date asks This event / This and
following / All events; "this event" takes the date out of the series (`exdates`) and adds a single event in its place.

## What's inside

```
components/calendar/
  event-calendar.tsx   the shell: sidebar, toolbar, the view, dialogs; layout by its own width
  sidebar.tsx          New event (+ All-day, Out of office), the mini calendar, My calendars, Team calendars, Upcoming
  toolbar.tsx          Today, ‹ ›, the title as a month/year picker, view switcher, search, settings
  month-view.tsx       the month grid, continuous multi-day bars, + N more, drag to move and to create
  time-grid.tsx        week and day: all-day row, side-by-side overlaps, now line, drag to create/move/resize, slot cursor
  agenda-view.tsx      day groups, Day 2 of 4, earlier events, loads more on scroll
  event-item.tsx       chips, bars and blocks (and what clicking, double-clicking and keys do to them)
  event-popovers.tsx   hover card, quick view, quick create
  event-dialog.tsx     the full editor; fields.tsx (typed times, dates, people, repeat, reminders); description-editor.tsx (TipTap, loaded on demand)
  dialogs.tsx          confirm, repeating-event scope, shortcuts, phone sheets
  store.ts, commands.ts, actions.ts   one typed store; commands with toasts and Undo; pure edits
  logic.ts, recurrence.ts, format.ts, tz.ts   ranges, layouts, search; series; the one date/time formatter; time zones
  data.ts, people.ts   the demo calendar and team
  ui/                  the shadcn/ui primitives it uses, in their Base UI flavour
```

## Keyboard

`M` `W` `D` `A` views · `T` today · `J` / `K` next / previous · `C` new event · `/` search · `[` sidebar · `?` all of
them. Arrow keys move through the month grid and the time slots, `Enter` opens a day or an event, `Space` picks up an
event to move with the arrows, `Delete` asks before deleting. Shortcuts pause while you type.

## Develop

```bash
npm install
npm run dev        # http://localhost:6301
npm test           # unit tests (time zones, formatting, recurrence, layout, edits)
npm run build && npm run start:lan   # http://localhost:6300, also from phones on the same Wi-Fi
node scripts/e2e.mjs                 # clicks through every feature against :6300 (installed Chrome)
node scripts/a11y.mjs                # axe on ten screens, light and dark
npm run shots                        # screenshots at 1440 / 1280 / 1024 / 768 / 390, light and dark
npm run registry && npm run zip      # what UpFork lists (registry/) and daybook.zip
```

Photos: `public/images/avatars/` (sources and licence in `CREDITS.md` there).
