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