Overview

The day, week, and month calendar views are created using separate React calendar components. The app uses the DayPilot Lite open-source scheduling library.

  • The view are switched by hiding/showing the individual components.

  • All components share the same data source and are updated automatically when you load the calendar data.

  • You can switch the visible date by simply updating a state variable.

  • Separate components let you customize each view invidually.

This tutorial assumes that you are already familiar with using the React Calendar from DayPilot in your application. For an introduction, please see the React Weekly Calendar (Open-Source) tutorial.

License

Apache License 2.0

Daily Calendar View in React

Daily Calendar View in React

The daily calendar is created using the React Calendar component from the open-source DayPilot Lite for JavaScript library. This calendar component displays days as columns and time slots as rows.

We will switch the Calendar component to a day view using the viewType property (viewType={"Day"}).

<DayPilotCalendar
  viewType={"Day"}
  startDate={startDate}
  events={events}
  visible={view === "Day"}
  durationBarVisible={false}
  onTimeRangeSelected={onTimeRangeSelected}
  controlRef={setDayView}
/>

Weekly Calendar View in React

Weekly Calendar View in React

The weekly calendar can be created using the same component. We just need to add viewType={"Week"} to the calendar configuration.

<DayPilotCalendar
  viewType={"Week"}
  startDate={startDate}
  events={events}
  visible={view === "Week"}
  durationBarVisible={false}
  onTimeRangeSelected={onTimeRangeSelected}
  controlRef={setWeekView}
/>

Monthly Calendar View in React

Monthly Calendar View in React

The monthly calendar view requires the React monthly calendar component. This component displays one week per row, one day per cell.

<DayPilotMonth
  startDate={startDate}
  events={events}
  visible={view === "Month"}
  eventBarVisible={false}
  onTimeRangeSelected={onTimeRangeSelected}
  controlRef={setMonthView}
/>

Loading Calendar Events

You might have noticed that all the calendar components specify an events attribute that points to the events state variable:

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

// ...

return (
  <div>
    <DayPilotCalendar
      viewType={"Day"}
      events={events}
      ...
    />
    <DayPilotCalendar
      viewType={"Week"}
      events={events}
      ...
    />
    <DayPilotMonth
      events={events}
      ...
    />
  </div>
);

Updating the events state variable is the easiest way to update the calendar data for all components at once.

We do this in a useEffect() block that uses an empty array ([]) as the dependency list. That makes it run once, during the initial page load.

useEffect(() => {

  const data = [
    {
      id: 1,
      text: "Event 1",
      start: DayPilot.Date.today().addHours(9),
      end: DayPilot.Date.today().addHours(11),
    },
    {
      id: 2,
      text: "Event 2",
      start: DayPilot.Date.today().addHours(10),
      end: DayPilot.Date.today().addHours(12),
      backColor: "#93c47d",
      borderColor: "darker"
    },
    {
      id: 9,
      text: "Event 9",
      start: DayPilot.Date.today().addHours(13),
      end: DayPilot.Date.today().addHours(15),
      backColor: "#76a5af", // Teal background
      borderColor: "darker"
    },
    {
      id: 3,
      text: "Event 3",
      start: DayPilot.Date.today().addDays(1).addHours(9),
      end: DayPilot.Date.today().addDays(1).addHours(11),
      backColor: "#ffd966", // Yellow background
      borderColor: "darker"
    },
    {
      id: 4,
      text: "Event 4",
      start: DayPilot.Date.today().addDays(1).addHours(11).addMinutes(30),
      end: DayPilot.Date.today().addDays(1).addHours(13).addMinutes(30),
      backColor: "#f6b26b", // Orange background
      borderColor: "darker"
    },

    {
      id: 7,
      text: "Event 7",
      start: DayPilot.Date.today().addDays(1).addHours(14),
      end: DayPilot.Date.today().addDays(1).addHours(16),
      backColor: "#e691b8", // Pink background
      borderColor: "darker"
    },
    {
      id: 5,
      text: "Event 5",
      start: DayPilot.Date.today().addDays(4).addHours(9),
      end: DayPilot.Date.today().addDays(4).addHours(11),
      backColor: "#8e7cc3", // Purple background
      borderColor: "darker"
    },
    {
      id: 6,
      text: "Event 6",
      start: DayPilot.Date.today().addDays(4).addHours(13),
      end: DayPilot.Date.today().addDays(4).addHours(15),
      backColor: "#6fa8dc", // Light Blue background
      borderColor: "darker"
    },

    {
      id: 8,
      text: "Event 8",
      start: DayPilot.Date.today().addDays(5).addHours(13),
      end: DayPilot.Date.today().addDays(5).addHours(15),
      backColor: "#b6d7a8", // Light Green background
      borderColor: "darker"
    },

  ];

  setEvents(data);

}, [])

This example uses a simple static array. In your React application, you will need to replace it with your own data loading logic.

Switching the Day, Week, and Months Calendar Views in React

Switching the Day, Week, and Months Calendar Views in React

Now it’s time to add the logic that lets users of your React scheduling application switch the calendar views.

The first step will be to create a view state variable that stores the id of the current view ("Day", "Week", or "Month"). The default value is set to "Week". This option displays the weekly calendar view on startup.

const [view, setView] = useState("Week");

Now we can add the corresponding buttons to the JSX that will change the value of the view state variable on click.

Note that we also add a selected CSS class to the currently-selected button.

return (
  <div>
    <div className={"toolbar"}>
      <div class={"toolbar-group"}>
        <button onClick={() => setView("Day")} className={view === "Day" ? "selected" : ""}>Day</button>
        <button onClick={() => setView("Week")} className={view === "Week" ? "selected" : ""}>Week</button>
        <button onClick={() => setView("Month")} className={view === "Month" ? "selected" : ""}>Month</button>
      </div>
    </div>

    ...

  </div>
);

The calendar components representing the day, week and month views are hidden/displayed depending on the view state variable value. The visible attribute of each calendar component will only be set to true when the view value equals the corresponding calendar view.

return (
  <div>

    ...

    <DayPilotCalendar
      viewType={"Day"}
      visible={view === "Day"}
      ...
    />
    <DayPilotCalendar
      viewType={"Week"}
      visible={view === "Week"}
      ...
    />
    <DayPilotMonth
      visible={view === "Month"}
      ...
    />
      
  </div>
);

Changing the Selected Date using a Date Picker

Changing the Selected Date using a Date Picker

In this step, we will add an option to change the visible date using a React date picker component. The date picker (<DayPilotNavigator> component) displays a small calendar on the left side of the page and highlights the currently-selected date.

The date picker supports several selection types ("Day", "Week" and "Month") that correspond to our calendar views. It always remembers the date that was clicked but it automatically extends the selection to the specified date range. Below, you can see that we have bound the selectMode attribute to the view state variable. This way, the selection will be updated automatically when the user selects a different calendar view.

The onTimeRangeSelected event handler is fired when the users selects a different date. We store the new date in the startDate state variable which in turn updates all calendar components.

Another trick is to point the events attribute (linked internally to events.list) to the events state variable. The date picker will load the calendar data and highlight all days with at least one event (busy days).

const [startDate, setStartDate] = useState(DayPilot.Date.today());

// ...

return (
  <div className={"container"}>
    <div className={"navigator"}>
      <DayPilotNavigator
        selectMode={view}
        showMonths={3}
        skipMonths={3}
        onTimeRangeSelected={args => setStartDate(args.day)}
        events={events}
      />
    </div>
    <div className={"content"}>

      <DayPilotCalendar
        viewType={"Day"}
        startDate={startDate}
        events={events}
        visible={view === "Day"}
        durationBarVisible={false}
        onTimeRangeSelected={onTimeRangeSelected}
        controlRef={setDayView}
      />
      
      // ...
      
    </div>
  </div>
);

Using a Button to Change the Selected Date in the Calendar

Using a Button to Change the Selected Date in the Calendar

In this section, we will take a look at how to change the visible date manually. Let’s add a “Today” button to our calendar toolbar:

<div className={"toolbar"}>
  <!-- ... -->
  <button onClick={() => setStartDate(DayPilot.Date.today())} className={"standalone"}>Today</button>
</div>

As you can see, the onClick event handler updates the startDate state variable using setStartDate() function.

The startDate value is used by all calendar components for the visible date, the change will be detected by React and all calendar view will be updated automatically.

Creating Events in the Day, Week, and Month Views of the React Calendar

Creating Events in the Day, Week, and Month Views of the React Calendar

The React calendar has a built-in support for drag-and-drop time range selection. This feature can be used easily to create new calendar events.

The calendar component fires onTimeRangeSelected event handler whenever the users completes a time range selection in the calendar grid.

The syntax of the onTimeRangeSelected event in all calendar components is compatible, so we can point all the components to the same event handler.

return (
  <div>

    ...

    <DayPilotCalendar
      viewType={"Day"}
      onTimeRangeSelected={onTimeRangeSelected}
      ...
    />
    <DayPilotCalendar
      viewType={"Week"}
      onTimeRangeSelected={onTimeRangeSelected}
      ...
    />
    <DayPilotMonth
      onTimeRangeSelected={onTimeRangeSelected}
      ...
    />
      
  </div>
);

Our onTimeRangeSelected function gets the reference to the source component from args.control and uses the clearSelection() method to remove the current selection.

It opens a modal dialog that asks the user for event details (in this example it’s just a simple modal dialog with the event text).

If the creation of a new event is confirmed, it adds a new event with the specified parameters (start and end date, event text) to the events array. This updates all calendar views automatically.

const onTimeRangeSelected = async (args) => {
  const dp = args.control;
  const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
  dp.clearSelection();
  if (modal.canceled) {
    return;
  }
  const e = {
    start: args.start,
    end: args.end,
    text: modal.result
  };
  setEvents([...events, e]);
};

Full Source Code

And here is the full JavaScript source code of our Calendar.js React component that shows day, week and month calendar views.

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

const Calendar = () => {

  const [view, setView] = useState("Week");
  const [startDate, setStartDate] = useState(DayPilot.Date.today());
  const [events, setEvents] = useState([]);

  const [dayView, setDayView] = useState();
  const [weekView, setWeekView] = useState();
  const [monthView, setMonthView] = useState();

  const onTimeRangeSelected = async (args) => {
    const dp = args.control;
    const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
    dp.clearSelection();
    if (modal.canceled) {
      return;
    }
    const e = {
      start: args.start,
      end: args.end,
      text: modal.result
    };
    setEvents([...events, e]);
  };

  useEffect(() => {

    const data = [
      {
        id: 1,
        text: "Event 1",
        start: DayPilot.Date.today().addHours(9),
        end: DayPilot.Date.today().addHours(11),
      },
      {
        id: 2,
        text: "Event 2",
        start: DayPilot.Date.today().addHours(10),
        end: DayPilot.Date.today().addHours(12),
        backColor: "#93c47d",
        borderColor: "darker"
      },
      {
        id: 9,
        text: "Event 9",
        start: DayPilot.Date.today().addHours(13),
        end: DayPilot.Date.today().addHours(15),
        backColor: "#76a5af", // Teal background
        borderColor: "darker"
      },
      {
        id: 3,
        text: "Event 3",
        start: DayPilot.Date.today().addDays(1).addHours(9),
        end: DayPilot.Date.today().addDays(1).addHours(11),
        backColor: "#ffd966", // Yellow background
        borderColor: "darker"
      },
      {
        id: 4,
        text: "Event 4",
        start: DayPilot.Date.today().addDays(1).addHours(11).addMinutes(30),
        end: DayPilot.Date.today().addDays(1).addHours(13).addMinutes(30),
        backColor: "#f6b26b", // Orange background
        borderColor: "darker"
      },

      {
        id: 7,
        text: "Event 7",
        start: DayPilot.Date.today().addDays(1).addHours(14),
        end: DayPilot.Date.today().addDays(1).addHours(16),
        backColor: "#e691b8", // Pink background
        borderColor: "darker"
      },
      {
        id: 5,
        text: "Event 5",
        start: DayPilot.Date.today().addDays(4).addHours(9),
        end: DayPilot.Date.today().addDays(4).addHours(11),
        backColor: "#8e7cc3", // Purple background
        borderColor: "darker"
      },
      {
        id: 6,
        text: "Event 6",
        start: DayPilot.Date.today().addDays(4).addHours(13),
        end: DayPilot.Date.today().addDays(4).addHours(15),
        backColor: "#6fa8dc", // Light Blue background
        borderColor: "darker"
      },

      {
        id: 8,
        text: "Event 8",
        start: DayPilot.Date.today().addDays(5).addHours(13),
        end: DayPilot.Date.today().addDays(5).addHours(15),
        backColor: "#b6d7a8", // Light Green background
        borderColor: "darker"
      },

    ];

    setEvents(data);

  }, []);

  return (
    <div className={"container"}>
      <div className={"navigator"}>
        <DayPilotNavigator
          selectMode={view}
          showMonths={3}
          skipMonths={3}
          onTimeRangeSelected={args => setStartDate(args.day)}
          events={events}
        />
      </div>
      <div className={"content"}>
        <div className={"toolbar"}>
          <div className={"toolbar-group"}>
            <button onClick={() => setView("Day")} className={view === "Day" ? "selected" : ""}>Day</button>
            <button onClick={() => setView("Week")} className={view === "Week" ? "selected" : ""}>Week</button>
            <button onClick={() => setView("Month")} className={view === "Month" ? "selected" : ""}>Month</button>
          </div>
          <button onClick={() => setStartDate(DayPilot.Date.today())} className={"standalone"}>Today</button>
        </div>

        <DayPilotCalendar
          viewType={"Day"}
          startDate={startDate}
          events={events}
          visible={view === "Day"}
          durationBarVisible={false}
          onTimeRangeSelected={onTimeRangeSelected}
          controlRef={setDayView}
        />
        <DayPilotCalendar
          viewType={"Week"}
          startDate={startDate}
          events={events}
          visible={view === "Week"}
          durationBarVisible={false}
          onTimeRangeSelected={onTimeRangeSelected}
          controlRef={setWeekView}
        />
        <DayPilotMonth
          startDate={startDate}
          events={events}
          visible={view === "Month"}
          eventBarVisible={false}
          onTimeRangeSelected={onTimeRangeSelected}
          controlRef={setMonthView}
        />
      </div>
    </div>
  );
}
export default Calendar;

Download

You can download the full React 18 project at the top of the tutorial.

History

  • June 16, 2024: Initial version.