The React Calendar displays time vertically, with days or resources as columns. Use a week view to follow appointments across dates, or a resource view to compare several schedules on the same day. Users can select a time range, move an appointment to another column, or resize its duration.

Choose DayPilot Lite, the open-source edition under the Apache License 2.0, or DayPilot Pro, the commercial edition with additional scheduling features. Both provide React components, TypeScript definitions, day/week views, resource columns, and custom event rendering with JSX.

Try the day/week/month calendar · Try the resource calendar · Configure a calendar in UI Builder

React Event Calendar Component (DayPilot)

React Calendar Features

DayPilot Lite and Pro

  • Day, week, and custom day views. Show one day, a work week, a full week, or a chosen number of days. Add previous/next buttons or a React date picker to move through the schedule. A month overview uses the separate React monthly calendar; the combined-view tutorial below shows how to connect them.

  • Resources as columns. Use a resource calendar to compare the daily schedules of people, rooms, or equipment side by side. Each event's resource matches a column ID. Changing the column name keeps that association; moving an event between resource columns changes its assignment.

  • Event creation and editing. Handle a time-range selection to open an editor or create an event. Support drag-and-drop moving and resizing, and display a delete icon. The callbacks let your React application update its state and save the changes to your backend.

  • Custom event content. Use colors, labels, icons, and event actions to make appointments easy to recognize. Render JSX inside events, including React components with their own click handlers, and use CSS themes to match the calendar to your application.

  • Working hours and local date formats. Set business hours, time-slot duration, and the first day of the week. Choose a locale for date and time formatting, and supply your application's own translated labels.

Additional DayPilot Pro Features

  • Grouped resource schedules. Organize rooms by location or staff by team using a column-header hierarchy. You can also group resource columns under dates when users need to plan across several days.

  • Wide calendars. Keep resource columns at a fixed width and use horizontal scrolling to reach more resources. This keeps a busy schedule readable without squeezing every column into the available window. You can enable progressive event rendering for fixed-width calendars to limit rendering work around the viewport.

  • Overnight and all-day scheduling. Configure overnight schedules for shifts that cross midnight. Display all-day events above the time grid when an item belongs to a day rather than a specific hour.

  • Touch interaction. Support scheduling gestures on touch devices. Combine touch support with an application layout and controls that suit the available screen space.

  • Export. Export a JPEG, PNG, or SVG image, embed an image in a PDF document, or create an Excel spreadsheet. The export guides describe format-specific libraries and limits.

See the feature matrix for the full edition comparison. For a horizontal timeline with resources as rows, use the React Scheduler.

Change the Resource Layout Using the Same Event Data

The grouped-resource example switches between five columns, fifty fixed-width columns, days containing resources, resources containing days, and resource groups. The grouped view shown here puts related resources under a shared header. Switch to resources/days to put dates under each resource: these child columns repeat the resource ID and specify their own date. The event's resource and date identify the matching column, so the same records fit several arrangements. Try the layout buttons (Pro).

The Lite resource example demonstrates a different choice: its group selector replaces the visible columns with Locations, People, or Tools. Click a header's edit icon to rename a resource in a dialog. The header customization hook supplies the icon, while the React application updates the column data. Try group selection and header editing.

Put React Controls Inside an Appointment

The JSX event-content example puts two information icons in the same event: one is an active area and the other is part of the JSX supplied through onBeforeEventDomAdd. Both open the event's details. Use an active area to position an action relative to the event box, or JSX to compose event content from React elements. The hook receives the current event as args.e and accepts the rendered element as args.element. Compare the two icons (Lite).

React Calendar Demos and Tutorials

These tutorials include downloadable projects and explain how each example works. The edition is shown for each tutorial so you can explore examples that match your package.

React Views and Navigation

React Content and Advanced Views

Next.js Calendars

Browse more React Calendar and Scheduler tutorials.

Configure a React Calendar Visually

The Calendar UI Builder lets you adjust calendar options in a live preview. Select a React target and the edition you want to use, then download a starter project with your configuration. Continue editing the options in your React code.

Installation

DayPilot Lite

Install @daypilot/daypilot-lite-react from npm:

npm install @daypilot/daypilot-lite-react

DayPilot Pro

At npm.daypilot.org, select React and copy the installation command for daypilot-pro-react. Licensed customers can obtain their package URL in the customer area.

The examples use JavaScript/JSX and function components with React 18 or later.

Display a Weekly Appointment Calendar

Start with a Monday-first week and one two-hour meeting.

Calendar.jsx

import {useState} from 'react';
import {DayPilot, DayPilotCalendar} from '@daypilot/daypilot-lite-react';

export default function Calendar() {
  const [events] = useState([
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ]);

  return <DayPilotCalendar
    startDate="2026-10-05"
    viewType="Week"
    weekStarts={1}
    events={events}
  />;
}

viewType: "Week" displays a week containing startDate. weekStarts: 1 makes Monday the first column. Events use a unique id, display text, and start/end date-times. The meeting ends at 12:00; event ends are exclusive.

The examples use Lite. For Pro, change the package import to daypilot-pro-react.

See event loading for data formats and loading options.

Navigate and Load Appointments

Previous and Next move by one week. Request appointments for that week, then replace the bound event array with the JSON array returned by your backend.

CalendarLoading.jsx

import {useState, useEffect} from 'react';
import {DayPilot, DayPilotCalendar} from '@daypilot/daypilot-lite-react';

export default function Calendar() {
  const [startDate, setStartDate] = useState(new DayPilot.Date('2026-10-05'));

  const [events, setEvents] = useState([]);

  useEffect(() => {
    let active = true;
    const start = startDate;
    const end = start.addDays(7);
    const url = `/api/events?start=${start}&end=${end}`;
    async function load() {
      try {
        const {data} = await DayPilot.Http.get(url);
        if (!active) { return; }
        setEvents(data);
      } catch {
        if (active) { await DayPilot.Modal.alert('Could not load data.'); }
      }
    }
    load();
    return () => { active = false; };
  }, [startDate]);

  function navigate(offset) {
    setStartDate(date => date.addDays(offset * 7));
  }

  return <>
    <button onClick={() => navigate(-1)}>Previous week</button>
    <button onClick={() => navigate(1)}>Next week</button>
    <DayPilotCalendar
      startDate={startDate}
      viewType="Week"
      weekStarts={1}
      events={events}
    />
  </>;
}

The /api/events URL represents your own backend. Return items that overlap the requested range: item start is before the requested end, and item end is after the requested start. Failed requests display a DayPilot dialog.

The effect cleanup prevents an older response from replacing data after another navigation action.

Create Appointments by Selecting Time

This complete variation of the first example handles time range selection. The selection supplies the dates; the dialog supplies the name.

CalendarCreation.jsx

import {useState} from 'react';
import {DayPilot, DayPilotCalendar} from '@daypilot/daypilot-lite-react';

export default function Calendar() {
  const [events] = useState([
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ]);

  return <DayPilotCalendar
    startDate="2026-10-05"
    viewType="Week"
    weekStarts={1}
    events={events}
    onTimeRangeSelected={async args => {
      const modal = await DayPilot.Modal.prompt('Appointment name:', 'New appointment');
      args.control.clearSelection();
      if (modal.canceled) { return; }
      args.control.events.add({
        id: DayPilot.guid(), text: modal.result,
        start: args.start, end: args.end
      });
    }}
  />;
}

Canceling the dialog leaves the data unchanged. events.add() inserts the new event locally. In an application with a backend, create the record with a POST request and use the returned ID before adding it to the view.

Move, Resize and Save Events

Moving changes the event position; resizing changes its duration. Both work in the first example without extra configuration. The component updates the display and the supplied data object automatically.

Use the callbacks after the edit to persist the result. This example sends the changed record to the backend; it does not reload the collection after each drag.

CalendarSaving.jsx

import {useState} from 'react';
import {DayPilot, DayPilotCalendar} from '@daypilot/daypilot-lite-react';

export default function Calendar() {
  const [events] = useState([
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ]);

  async function saveEvent(data) {
    try {
      await DayPilot.Http.put(`/api/events/${data.id}`, data);
    } catch {
      await DayPilot.Modal.alert('The change could not be saved.');
    }
  }

  return <DayPilotCalendar
    startDate="2026-10-05"
    viewType="Week"
    weekStarts={1}
    events={events}
    onEventMoved={args => saveEvent(args.e.data)}
    onEventResized={args => saveEvent(args.e.data)}
  />;
}

The /api/events/{id} endpoint accepts the updated JSON record. A failed save is reported while the local edit remains visible; add retry or rollback behavior to suit your application. To disable an interaction, set eventMoveHandling or eventResizeHandling to "Disabled".

Handle an Event Click

To display the clicked item’s name, add this prop to the existing component:

onEventClick={args => DayPilot.Modal.alert(DayPilot.Util.escapeHtml(args.e.text()))}

DayPilot.Modal.alert() accepts HTML. escapeHtml() displays the item’s name as plain text.

Render Custom React Content

This independent variation of the first example adds JSX to the event through onBeforeEventDomAdd.

CalendarContent.jsx

import {useState} from 'react';
import {DayPilot, DayPilotCalendar} from '@daypilot/daypilot-lite-react';

export default function Calendar() {
  const [events] = useState([
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ]);

  return <DayPilotCalendar
    startDate="2026-10-05"
    viewType="Week"
    weekStarts={1}
    events={events}
    onBeforeEventDomAdd={args => {
      args.element = <strong>{args.e.text()}</strong>;
    }}
  />;
}

Access the Calendar API

Use the event collection API to find and rename the meeting. The wrapper reference, button and handler are shown together.

CalendarApi.jsx

import {useState} from 'react';
import {DayPilot, DayPilotCalendar} from '@daypilot/daypilot-lite-react';

export default function Calendar() {
  const [calendar, setCalendar] = useState(null);

  const [events] = useState([
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ]);

  async function renameEvent() {
    const control = calendar;
    const event = control.events.find('meeting');
    const modal = await DayPilot.Modal.prompt('Event name:', event.text());
    if (modal.canceled) { return; }
    event.text(modal.result);
    control.events.update(event);
  }

  return <>
    <button disabled={!calendar} onClick={renameEvent}>Rename meeting</button>
    <DayPilotCalendar
      startDate="2026-10-05"
      viewType="Week"
      weekStarts={1}
      events={events}
      controlRef={setCalendar}
    />
  </>;
}

React receives the underlying control through controlRef. The wrapper creates and disposes it. See the DayPilot.Calendar API for methods, properties and callbacks.

Use Next.js

Place the introductory component in Calendar.jsx and add 'use client'; at the top. Create a client wrapper that loads it with server rendering disabled:

CalendarClient.jsx

'use client';

import dynamic from 'next/dynamic';

const Calendar = dynamic(() => import('./Calendar'), {ssr: false});

export default function CalendarClient() {
  return <Calendar />;
}

Import CalendarClient in your page and render <CalendarClient />. The Next.js client wrapper keeps the DayPilot component in the browser. The tutorials above provide complete project setups.

Availability

Availability of this feature in DayPilot editions:

ProductLitePro
DayPilot for JavaScript
DayPilot for ASP.NET WebForms
DayPilot for ASP.NET MVC
DayPilot for Java