Features

  • The application uses the React monthly calendar component from DayPilot Lite for JavaScript.

  • Calendar events are loaded using React automatic change detection.

  • The calendar component appearance is customized using CSS.

  • The calendar events use a context menu to provide additional options (delete an event, change color).

  • The React project download includes the open-source DayPilot Lite calendar/scheduling library.

License

Apache License 2.0

React Calendar UI Configurator

You can configure the calendar/scheduler components using the visual UI Builder application. Preview the configuration using a live calendar instance and download a ready-to-run React project.

Basic React Monthly Calendar Configuration

react monthly event calendar component configuration tutorial

You can add the monthly calendar component to your application using <DayPilotMonth> component which is included in the @daypilot/daypilot-lite-react package. 

The @daypilot/daypilot-lite-react package is hosted at npmjs.org - you can get add it to your React application using npm install command:

npm install @daypilot/daypilot-lite-react

We will create a new React component class (MonthlyCalendar) that will wrap the DayPilot calendar component and specify its properties. Our MonthlyCalendar component defines the calendar appearance and behavior using configuration properties and event handlers.

import React, {Component} from 'react';
import {DayPilot, DayPilotMonth} from "@daypilot/daypilot-lite-react";

class MonthlyCalendar extends Component {

  constructor(props) {
    super(props);

    this.calendarRef = React.createRef();

    this.state = {
      startDate: DayPilot.Date.today()
    };
  }

  render() {
    return (
      <div>
        <DayPilotMonth
          {...this.state}
          ref={this.calendarRef}
        />
      </div>
    );
  }
}

export default Month;

How to Load Calendar Events in React

react monthly calendar tutorial open source loading events

You can load events in componentDidMount() method using events property:

import React, {Component} from 'react';
import {DayPilot, DayPilotMonth} from "daypilot-pro-react";

class Month extends Component {

  constructor(props) {
    super(props);

    this.calendarRef = React.createRef();

    this.state = {
      startDate: "2022-11-01"
    };
  }

  componentDidMount() {

    // load event data
    this.setState({
      events: [
        {
          id: 1,
          text: "Event 1",
          start: "2022-11-08",
          end: "2022-11-09"
        },
        {
          id: 2,
          text: "Event 2",
          start: "2022-11-08",
          end: "2022-11-09"
        },
        {
          id: 3,
          text: "Event 3",
          start: "2022-11-08",
          end: "2022-11-08"
        },
        {
          id: 4,
          text: "Event 4",
          start: "2022-11-15",
          end: "2022-11-16"
        },
        {
          id: 5,
          text: "Event 5",
          start: "2022-11-15",
          end: "2022-11-16"
        },
      ]
    });

  }

  render() {
    return (
      <div>
        <DayPilotMonth
          {...this.state}
          ref={this.calendarRef}
        />
      </div>
    );
  }
}

export default Month;

The structure of event data items is described in DayPilot.Event.data documentation.

How to Style the Monthly Calendar Component

react monthly calendar tutorial open source styling

The calendar element dimensions can be modified using DayPilot.Month object properties. We will use the properties (eventHeight, headerHeight, and cellHeaderHeight) to increase the size of selected calendar elements.

import React, {Component} from 'react';
import {DayPilot, DayPilotMonth} from "daypilot-pro-react";
import "./MonthStyles.css";

class Month extends Component {

  constructor(props) {
    super(props);

    this.calendarRef = React.createRef();

    this.state = {
      startDate: DayPilot.Date.today(),
      eventHeight: 30,
      headerHeight: 30,
      cellHeaderHeight: 20
    };
  }

  componentDidMount() {

    // load event data
    this.setState({
      events: [
        {
          id: 1,
          text: "Event 1",
          start: "2022-11-08",
          end: "2022-11-09"
        },
        {
          id: 2,
          text: "Event 2",
          start: "2022-11-08",
          end: "2022-11-09"
        },
        {
          id: 3,
          text: "Event 3",
          start: "2022-11-08",
          end: "2022-11-08"
        },
        {
          id: 4,
          text: "Event 4",
          start: "2022-11-15",
          end: "2022-11-16"
        },
        {
          id: 5,
          text: "Event 5",
          start: "2022-11-15",
          end: "2022-11-16"
        },
      ]
    });

  }


  get calendar() {
    return this.calendarRef.current.control;
  }

  render() {
    var {...config} = this.state;
    return (
      <div>
        <DayPilotMonth
          {...config}
          ref={this.calendarRef}
        />
      </div>
    );
  }
}

export default Month;

The monthly calendar appearance is controlled by CSS. By default, the component uses a built-in theme (month_default). You can create your own CSS theme using the online theme designer or you can simply override selected styles of the built-in theme:

MonthStyles.css

.month_default_event {
    overflow: hidden;
    border-radius: 15px;
}
.month_default_event_inner {
    background: #636363;
    border-color: #777777;
    color: #fff;
    padding-left: 35px;
    border-radius: 15px;
}

.month_default_event_bar {
    left: 0px;
    width: 30px;

}
.month_default_event_bar_inner {
    background: #888888;
    border-radius: 15px;
    width: 30px;
}

React Monthly Calendar: How to Change the Event Appearance

react monthly calendar tutorial open source event appearance

You can customize the event appearance using data object properties. You can set the properties on the server side (add them to the JSON object after loading the data from a database). You can also add them on the client side using onBeforeEventRender to save bandwidth.

We will set event background color using backColor property of the event data object:

this.setState({
  startDate: "2022-11-01",
  events: [
    {
      id: 1,
      text: "Event 1",
      start: "2022-11-08",
      end: "2022-11-09",
      backColor: "#d5663e",
    },
    {
      id: 2,
      text: "Event 2",
      start: "2022-11-08",
      end: "2022-11-09",
      backColor: "#ecb823",
    },
    {
      id: 3,
      text: "Event 3",
      start: "2022-11-08",
      end: "2022-11-08",
      backColor: "#6aa84f",
    },
    {
      id: 4,
      text: "Event 4",
      start: "2022-11-15",
      end: "2022-11-16",
      backColor: "#3d85c6",
    },
    {
      id: 5,
      text: "Event 5",
      start: "2022-11-15",
      end: "2022-11-16"
    },
  ]
});

The backColor property defines the basic event color. We will use the onBeforeEventRender event handler to set a corresponding event bar color (the event bar appearance is changed to a circle using CSS set in the previous step).

constructor(props) {
  super(props);

  this.calendarRef = React.createRef();

  this.state = {
    onBeforeEventRender: args => {
      args.data.borderColor = "darker";
      if (args.data.backColor) {
        args.data.barColor = DayPilot.ColorUtil.darker(args.data.backColor, -1);
      }
    },
    // ...
  };
}

Monthly Calendar Context Menu

react monthly calendar scheduler tutorial open source event context menu

We will define a context menu using the contextMenu property of the scheduler component. The context menu can be activated by right-clicking the events.

constructor(props) {
  super(props);

  this.calendarRef = React.createRef();

  this.state = {
    contextMenu: new DayPilot.Menu({
      items: [
        {
          text: "Delete",
          onClick: args => {
            const e = args.source;
            this.calendar.events.remove(e);
          }
        },
        {
          text: "-"
        },
        {
          text: "Blue",
          icon: "icon icon-blue",
          color: "#3d85c6",
          onClick: args => this.updateColor(args.source, args.item.color)
        },
        {
          text: "Green",
          icon: "icon icon-green",
          color: "#6aa84f",
          onClick: args => this.updateColor(args.source, args.item.color)
        },
        {
          text: "Yellow",
          icon: "icon icon-yellow",
          color: "#ecb823",
          onClick: args => this.updateColor(args.source, args.item.color)
        },
        {
          text: "Red",
          icon: "icon icon-red",
          color: "#d5663e",
          onClick: args => this.updateColor(args.source, args.item.color)
        },
        {
          text: "Auto",
          color: null,
          onClick: args => this.updateColor(args.source, args.item.color)
        },

      ]
    }),
    
    // ...
    
  };
}

The first context menu item (“Delete”) removes the selected event from the calendar/scheduler using the events.remove() method. The event reference is accessible in the onClick handler as args.e so we can simply pass it to the events.remove() method.

The context menu also allows changing the event color. The menu items (“Blue”, “Green”, “Yellow”, “Red”, “Auto”) display a preview of the color using icon property and update the event object using updateColor() method on click:

updateColor(e, color) {
  e.data.backColor = color;
  this.calendar.events.update(e);
}

Full Source Code

src/month/MonthlyCalendar.js

import React, {Component} from 'react';
import {DayPilot, DayPilotMonth} from "@daypilot/daypilot-lite-react";
import "./MonthStyles.css";
import "./icons/style.css";

class MonthlyCalendar extends Component {

  constructor(props) {
    super(props);

    this.calendarRef = React.createRef();

    this.state = {
      eventHeight: 30,
      headerHeight: 30,
      cellHeaderHeight: 25,
      onBeforeEventRender: args => {
        args.data.borderColor = "darker";
        if (args.data.backColor) {
          args.data.barColor = DayPilot.ColorUtil.darker(args.data.backColor, -1);
        }
      },
      contextMenu: new DayPilot.Menu({
        items: [
          {
            text: "Delete",
            onClick: args => {
              const e = args.source;
              this.calendar.events.remove(e);
            }
          },
          {
            text: "-"
          },
          {
            text: "Blue",
            icon: "icon icon-blue",
            color: "#3d85c6",
            onClick: args => this.updateColor(args.source, args.item.color)
          },
          {
            text: "Green",
            icon: "icon icon-green",
            color: "#6aa84f",
            onClick: args => this.updateColor(args.source, args.item.color)
          },
          {
            text: "Yellow",
            icon: "icon icon-yellow",
            color: "#ecb823",
            onClick: args => this.updateColor(args.source, args.item.color)
          },
          {
            text: "Red",
            icon: "icon icon-red",
            color: "#d5663e",
            onClick: args => this.updateColor(args.source, args.item.color)
          },
          {
            text: "Auto",
            color: null,
            onClick: args => this.updateColor(args.source, args.item.color)
          },

        ]
      }),
      onTimeRangeSelected: async args => {
        const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");

        this.calendar.clearSelection();
        if (!modal.result) {
          return;
        }
        this.calendar.events.add({
          start: args.start,
          end: args.end,
          id: DayPilot.guid(),
          text: modal.result
        });
      },
    };
  }

  componentDidMount() {

    // load event data
    this.setState({
      startDate: "2022-11-01",
      events: [
        {
          id: 1,
          text: "Event 1",
          start: "2022-11-08",
          end: "2022-11-09",
          backColor: "#d5663e",
        },
        {
          id: 2,
          text: "Event 2",
          start: "2022-11-08",
          end: "2022-11-09",
          backColor: "#ecb823",
        },
        {
          id: 3,
          text: "Event 3",
          start: "2022-11-08",
          end: "2022-11-08",
          backColor: "#6aa84f",
        },
        {
          id: 4,
          text: "Event 4",
          start: "2022-11-15",
          end: "2022-11-16",
          backColor: "#3d85c6",
        },
        {
          id: 5,
          text: "Event 5",
          start: "2022-11-15",
          end: "2022-11-16"
        },
      ]
    });

  }

  updateColor(e, color) {
    e.data.backColor = color;
    this.calendar.events.update(e);
  }


  get calendar() {
    return this.calendarRef.current.control;
  }

  render() {
    return (
      <div>
        <DayPilotMonth
          {...this.state}
          ref={this.calendarRef}
        />
      </div>
    );
  }
}

export default MonthlyCalendar;

src/month/MonthStyles.css

/* calendar event */

.month_default_event {
    overflow: hidden;
    border-radius: 15px;
}
.month_default_event_inner {
    background: #636363;
    border-color: #777777;
    color: #fff;
    padding-left: 35px;
    border-radius: 15px;
}

.month_default_event_bar {
    left: 0px;
    width: 30px;

}
.month_default_event_bar_inner {
    background: #888888;
    border-radius: 15px;
    width: 30px;
}

/* context menu icons */
.icon:before {
    position: absolute;
    left: 0px;
    margin-left: 8px;
    margin-top: 3px;
    width: 14px;
    height: 14px;
    content: '';
}

.icon-blue:before { background-color: #3c78d8; }
.icon-green:before { background-color: #6aa84f; }
.icon-yellow:before { background-color: #e69138; }
.icon-red:before { background-color: #cc0000; }

History

  • August 17, 2022: Switched to the open-source DayPilot Lite for JavaScript 2022.3.432 (available as 3.10.1 in the NPM registry). Upgraded to React 18. Updated event styles and colors.

  • December 14, 2020: Upgraded to DayPilot Pro for JavaScript 2020.4.4788, React 17.

  • September 23, 2019: Upgraded to DayPilot Pro for JavaScript 2019.3.4039, styling updates.

  • June 15, 2018: Initial release