Features

  • This React 18 application builds an event calendar/scheduler UI using React Event Calendar component from the free DayPilot Lite open-source calendar library.

  • The React calendar appearance is customized using CSS.

  • The built-in date picker can be used for switching the visible week.

  • A React project with a complete source code is available for download.

License

Apache License 2.0

React Calendar UI Configurator

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

How to install the React calendar component?

react weekly calendar component open source day view

You can add the React calendar component to your JSX using <DayPilotCalendar> tag.

This example creates a new functional React component called Calendar and adds the <DayPilotCalendar> component with the default configuration.

import React from 'react';
import { DayPilotCalendar } from "@daypilot/daypilot-lite-react";

const Calendar = () => {
    return (
        <div>
            <DayPilotCalendar />
        </div>
    );
}

export default Calendar;

Out of the box, the React calendar component displays the current day. Later in this tutorial, we will see how to enable a week view and set a custom start date.

The DayPilotCalendar React component is available as part of the open-source DayPilot Lite calendar/scheduling library. The React package is available at NPM (@daypilot/daypilot-lite-react).

You can add it to your React application using npm or yarn:

NPM

npm install @daypilot/daypilot-lite-react

Yarn

yarn add @daypilot/daypilot-lite-react

How to add a weekly calendar to your React application?

react weekly calendar component open source date

You can add a weekly calendar by changing the React calendar component configuration object. By default, the calendar displays one day (day view). There are several modes available:

  • Day

  • Week

  • WorkWeek

  • Days (custom number of days)

  • Resources

The “Resources” calendar mode was added in version 2022.2384. It lets you add a resource calendar to your React application. This mode displays custom resources (people, rooms, locations, tools) as columns in the scheduling calendar. To learn more about using the resource calendar in React, see the React Resource Calendar with Editable Columns (Open-Source) tutorial:

react resource calendar tutorial open source

We will switch the calendar to the week view using viewType property:

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

const Calendar = () => {
    const [config, setConfig] = useState({
        viewType: "Week"
    });

    return (
        <div>
            <DayPilotCalendar {...config} />
        </div>
    );
}

export default Calendar;

Note that we have added a config state object to our Calendar component. It holds the calendar configuration properties (and event handlers). The ...config syntax is used to pass all properties of the config state object as props to the DayPilotCalendar component.

In the next steps, we will use the config object to add more properties that will customize the calendar view.

How to customize the appearance of the React calendar?

We will make a couple of changes to the calendar appearance using the configuration object and CSS.

By default, a duration bar is displayed on the left side of calendar events, representing the actual event duration. Also, the color of the duration bar can be customized based on the event type or status.

react weekly calendar component tutorial open source duration bar

In our React application, we will turn the duration bar off using the durationBarVisible property:

react weekly calendar component tutorial open source duration bar off

import React, { useState } from 'react';
import { DayPilotCalendar } from "@daypilot/daypilot-lite-react";
import "./CalendarStyles.css";

const Calendar = () => {
    const [config, setConfig] = useState({
      // ...
      durationBarVisible: false,
      // ...
    });

    return (
        <div>
            <DayPilotCalendar {...config} />
        </div>
    );
}

export default Calendar;

In the next step, we will customize the appearance of the calendar events using CSS.

The calendar styles are set by a CSS theme. The calendar component includes a built-in theme which defines the default appearance ("calendar_default"). 

You can create your own theme using the online theme designer or you can simply override selected styles of the built-in theme. That's what we are going to do in this example:

CalendarStyles.css

/* adjusting the built-in theme */


/* calendar event */
.calendar_default_event_inner {
    background: #2e78d6;
    color: #fff;
    border: none;
    border-radius: 5px;
    font-size: 10pt;
    padding: 5px;
    opacity: 0.8;
}

This CSS overrides the default calendar event appearance, using white text on a semi-transparent light blue background:

react weekly calendar component tutorial open source css

How to add a React date picker to the calendar?

react weekly calendar component tutorial open source date picker

In order to let users change the visible week, we will use a React date picker component called Navigator. You can add the navigator to the React JSX page using <DayPilotNavigator> tag:

import React, { useState } from 'react';
import { DayPilotCalendar, DayPilotNavigator } from "@daypilot/daypilot-lite-react";
import "./CalendarStyles.css";

const Calendar = () => {

    // ...

    return (
        <div>
            <DayPilotNavigator />
            <DayPilotCalendar {...config} />
        </div>
    );
}

export default Calendar;

The navigator fires the onTimeRangeSelected event whenever a user clicks a date:

import React, { useState } from 'react';
import { DayPilotCalendar, DayPilotNavigator } from "@daypilot/daypilot-lite-react";
import "./CalendarStyles.css";

const Calendar = () => {

    // ...

    return (
        <div>
            <DayPilotNavigator
                onTimeRangeSelected={ args => {
                    console.log("You clicked: " + args.day);
                }}
            />
            <DayPilotCalendar {...config} />
        </div>
    );
}

export default Calendar;

We will use the date picker onTimeRangeSelected event to change the startDate property of the Calendar component:

First, it is necessary to get access to the DayPilot.Calendar object that controls the weekly calendar. We add a ref attribute to the React calendar component (<DayPilotCalendar>). This ref attribute will store a reference to the DayPilotCalendar component. We initialize this reference using the useRef() hook in React. The useRef() hook creates a mutable object whose .current property is initialized to the argument passed to useRef(). This ref object will persist for the full lifetime of the component and you will be able to access it in any part of your component code, including event handlers and effects.

import React, { useState, useRef } from 'react';
import { DayPilotCalendar, DayPilotNavigator } from "@daypilot/daypilot-lite-react";
import "./CalendarStyles.css";

const Calendar = () => {

    // ...
    
    const calendarRef = useRef();

    return (
        <div>
            <DayPilotNavigator
                onTimeRangeSelected={ args => {
                    console.log("You clicked: " + args.day);
                }}
            />
            <DayPilotCalendar {...config} ref={calendarRef} />
        </div>
    );
}

export default Calendar;

Now we can use calendarRef.current.control to access the DayPilot.Calendar object and call its update() method to change the visible date.

This is how the date-changing logic looks now in our application:

import React, { useState, useRef } from 'react';
import { DayPilotCalendar, DayPilotNavigator } from "@daypilot/daypilot-lite-react";
import "./CalendarStyles.css";

const styles = {
  wrap: {
    display: "flex"
  },
  left: {
    marginRight: "10px"
  },
  main: {
    flexGrow: "1"
  }
};

const Calendar = () => {
    const [config, setConfig] = useState({
      viewType: "Week",
      durationBarVisible: false
    });
    
    const calendarRef = useRef();

    const handleTimeRangeSelected = args => {
      calendarRef.current.control.update({
        startDate: args.day
      });
    }

    return (
        <div style={styles.wrap}>
            <div style={styles.left}>
                <DayPilotNavigator
                    selectMode={"Week"}
                    showMonths={3}
                    skipMonths={3}
                    onTimeRangeSelected={handleTimeRangeSelected}
                />
            </div>
            <div style={styles.main}>
                <DayPilotCalendar {...config} ref={calendarRef} />
            </div>
        </div>
    );
}

export default Calendar;

How to load calendar events in React?

react weekly calendar component tutorial open source loading events

The calendar event data can be loaded using the update() method of the Calendar component. The events property of the options parameter specifies the new event data set:

useEffect(() => {
  // load event data
  calendarRef.current.control.update({
    startDate: "2023-10-02",
    events: [
      {
        id: 1,
        text: "Event 1",
        start: "2023-10-02T10:30:00",
        end: "2023-10-02T13:00:00"
      },
      {
        id: 2,
        text: "Event 2",
        start: "2023-10-03T09:30:00",
        end: "2023-10-03T11:30:00",
        backColor: "#6aa84f"
      },
      {
        id: 3,
        text: "Event 3",
        start: "2023-10-03T12:00:00",
        end: "2023-10-03T15:00:00",
        backColor: "#f1c232"
      },
      {
        id: 4,
        text: "Event 4",
        start: "2023-10-01T11:30:00",
        end: "2023-10-01T14:30:00",
        backColor: "#cc4125"
      },
    ]
  });
}, []);

Full Source Code

And here is the full source code of our React calendar/scheduler component that displays events customized using CSS:

Calendar.js

import React, { useState, useRef, useEffect } from 'react';
import { DayPilot, DayPilotCalendar, DayPilotNavigator } from "@daypilot/daypilot-lite-react";
import "./CalendarStyles.css";

const styles = {
  wrap: {
    display: "flex"
  },
  left: {
    marginRight: "10px"
  },
  main: {
    flexGrow: "1"
  }
};

const Calendar = () => {
  const calendarRef = useRef()

  const editEvent = async (e) => {
    const dp = calendarRef.current.control;
    const modal = await DayPilot.Modal.prompt("Update event text:", e.text());
    if (!modal.result) { return; }
    e.data.text = modal.result;
    dp.events.update(e);
  };

  const [calendarConfig, setCalendarConfig] = useState({
    viewType: "Week",
    durationBarVisible: false,
    timeRangeSelectedHandling: "Enabled",
    onTimeRangeSelected: async args => {
      const dp = calendarRef.current.control;
      const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
      dp.clearSelection();
      if (!modal.result) { return; }
      dp.events.add({
        start: args.start,
        end: args.end,
        id: DayPilot.guid(),
        text: modal.result
      });
    },
    onEventClick: async args => {
      await editEvent(args.e);
    },
    contextMenu: new DayPilot.Menu({
      items: [
        {
          text: "Delete",
          onClick: async args => {
            const dp = calendarRef.current.control;
            dp.events.remove(args.source);
          },
        },
        {
          text: "-"
        },
        {
          text: "Edit...",
          onClick: async args => {
            await editEvent(args.source);
          }
        }
      ]
    }),
    onBeforeEventRender: args => {
      args.data.areas = [
        {
          top: 3,
          right: 3,
          width: 20,
          height: 20,
          symbol: "icons/daypilot.svg#minichevron-down-2",
          fontColor: "#fff",
          toolTip: "Show context menu",
          action: "ContextMenu",
        },
        {
          top: 3,
          right: 25,
          width: 20,
          height: 20,
          symbol: "icons/daypilot.svg#x-circle",
          fontColor: "#fff",
          action: "None",
          toolTip: "Delete event",
          onClick: async args => {
            const dp = calendarRef.current.control;
            dp.events.remove(args.source);
          }
        }
      ];


      const participants = args.data.participants;
      if (participants > 0) {
        // show one icon for each participant
        for (let i = 0; i < participants; i++) {
          args.data.areas.push({
            bottom: 5,
            right: 5 + i * 30,
            width: 24,
            height: 24,
            action: "None",
            image: `https://picsum.photos/24/24?random=${i}`,
            style: "border-radius: 50%; border: 2px solid #fff; overflow: hidden;",
          });
        }
      }
    }
  });

  useEffect(() => {
    const events = [
      {
        id: 1,
        text: "Event 1",
        start: "2023-10-02T10:30:00",
        end: "2023-10-02T13:00:00",
        participants: 2,
      },
      {
        id: 2,
        text: "Event 2",
        start: "2023-10-03T09:30:00",
        end: "2023-10-03T11:30:00",
        backColor: "#6aa84f",
        participants: 1,
      },
      {
        id: 3,
        text: "Event 3",
        start: "2023-10-03T12:00:00",
        end: "2023-10-03T15:00:00",
        backColor: "#f1c232",
        participants: 3,
      },
      {
        id: 4,
        text: "Event 4",
        start: "2023-10-01T11:30:00",
        end: "2023-10-01T14:30:00",
        backColor: "#cc4125",
        participants: 4,
      },
    ];

    const startDate = "2023-10-02";

    calendarRef.current.control.update({startDate, events});
  }, []);

  return (
    <div style={styles.wrap}>
      <div style={styles.left}>
        <DayPilotNavigator
          selectMode={"Week"}
          showMonths={3}
          skipMonths={3}
          startDate={"2023-10-02"}
          selectionDay={"2023-10-02"}
          onTimeRangeSelected={ args => {
            calendarRef.current.control.update({
              startDate: args.day
            });
          }}
        />
      </div>
      <div style={styles.main}>
        <DayPilotCalendar
          {...calendarConfig}
          ref={calendarRef}
        />
      </div>
    </div>
  );
}

export default Calendar;

History