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
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
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
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
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
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
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
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.