Telerik blogs
ReactT2 Dark_1200x303

Today we’ll explore the differences between a React calendar and a React scheduler component so you know when to choose one over the other. We’ll also take a look at how to implement a few real-world examples.

For many years, we have used calendars in various shapes or forms. In the past, we had them hanging on the walls showing us dates and sometimes we were marking them for special occasions. However, things changed as computers and smartphones became more common. Nowadays, the concept of a calendar can be used to create a variety of applications.

The only thing is, there are different styles of calendar components with various features. It can be confusing which is the most appropriate solution for your app. So what are the basic differences between a React calendar and a React scheduler? Let’s walk through these differences, and then look at some real-life examples.

React Calendar or React Scheduler?

A React calendar component is a good choice when you need to allow users to select a specific date, like if your app has a form field for date of birth or employee start date. Another good example would be an application that allows users to book appointments. A user would be able to select a specific date and time slot from available options. For scenarios like this, a calendar component is probably the best bet.

On the other hand, a React scheduler might be used for viewing an agenda at a glance or scheduling events and tasks. These types of components can be used to see multiple agendas at once, like your work schedule and childcare plans. What’s more, they can provide a richer overview of your tasks, as often you can view your agendas by day, week or even month.

So a calendar is more likely used for a big-picture calendar, while a scheduler is used for detailed schedules/agendas.

Now let’s explore some real examples of how these two different types of components can be used, even looking at some actual code implementation. The full code examples are available in this GitHub repository. You can also try out the interactive example below.

Project Setup

Before we dive in deeper, let’s set up a React project. To quickly scaffold one, you can use Create React App or Vite. For this demo, we are going to use Create React App. You can create a React project by running one of the below commands in your terminal.

npx create-react-app my-kendo-react-calendars  
cd my-kendo-react-calendars  
npm start // or yarn start  

I’m going to use the KendoReact Calendar and Scheduler components for these demos. So we need to install a few packages that are needed for using KendoReact Calendar and Scheduler components.

Note: KendoReact is a commercial UI component library, and as a part of this you will need to provide a license key when you use the components in your React projects. You can snag a license key through a free trial or by owning a commercial license. For more information, you can head over to the KendoReact Licensing page.

// npm  
npm install @progress/kendo-react-scheduler @progress/kendo-react-popup @progress/kendo-react-dialogs @progress/kendo-react-dateinputs @progress/kendo-react-dropdowns @progress/kendo-react-inputs @progress/kendo-react-buttons @progress/kendo-date-math @progress/kendo-react-form @progress/kendo-react-intl @progress/kendo-drawing @progress/kendo-react-treeview @progress/kendo-react-animation @progress/kendo-react-common @progress/kendo-licensing @progress/kendo-theme-default  

Next, replace the contents of App.js and App.css files.

src/App.js

import '@progress/kendo-theme-default/dist/all.css';  
import "./App.css";  
function App() {  
  return <div className="App"></div>;  
}  
  
export default App;  

src/App.css

.App {  
  max-width: 40rem;  
  margin: 2rem auto;  
}  

That’s it for the project setup.

React Calendar

A React calendar component can be used when you need to allow users to select a specific date. A very common example of using a calendar is for picking your date of birth. Users need to be able to select the year, month and day they were born.

This can be achieved by using a simple input, but a calendar component can provide a better user experience. It will also work better on touch-screen devices, as you don’t have to type anything. Instead, you only need to click or touch a few times to select the date you want.

Selecting a Date of Birth

Let’s start by implementing a simple calendar that will allow users to select their date of birth. We will need to implement the Calendar component from the @progress/kendo-react-dateinputs library. Below you can see the code for it.

src/components/calendar/PickDateOfBirth.js

import { Calendar } from "@progress/kendo-react-dateinputs";
import { useState } from "react";

const PickDateOfBirth = props => {
  const [date, setDate] = useState(null);

  return (
    <div className="k-my-8">
      <div className="k-mb-6 k-font-weight-bold">Date of birth</div>

      <Calendar value={date} onChange={e => setDate(e.value)} />
      <div className="k-mt-4">Selected date: {date?.toDateString()}</div>
    </div>
  );
};

export default PickDateOfBirth;

We have one useState to store the selected date. We pass value and onChange props to the Calendar component to keep the state in sync. Finally, we render the selected date below the Calendar component. We also need to update the App.js file to include our PickDateOfBirth component.

src/App.js

import "@progress/kendo-theme-default/dist/all.css";
import "./App.css";
import PickDateOfBirth from "./components/calendar/PickDateOfBirth";

function App() {
  return (
    <div className="App">
      <PickDateOfBirth />
    </div>
  );
}

export default App;

As the gif below shows, we have a beautiful calendar working out of the box, and we can save the date selected by a user. This example is very simple, so let’s create something a bit more complex.

The user first scrolls through a list of years, then months within that year (which also loop to other years' months), and then the individual date can be selected from a calendar view.

Book a Driving Lesson

The Calendar component can be composed with other functionality to create more complex features.

Imagine you want to book a driving lesson with your instructor. First, you would need to be able to select the day on which you want to drive. After that, you should be presented with a list of time slots that the instructor has available. Finally, you should be able to select one of the time slots. Below you can see the code for implementing that functionality.

src/components/calendar/BookDrivingSlot.js

import { Calendar } from "@progress/kendo-react-dateinputs";
import { useEffect, useRef, useState } from "react";

const times = [
  "08:00 - 10:00",
  "10:00 - 12:00",
  "12:00 - 14:00",
  "14:00 - 16:00",
  "16:00 - 18:00",
  "18:00 - 20:00",
];

const getRandomNumInRange = (min, max) => {
  return Math.floor(Math.random() * (max - min) + min);
};

const pickSlotTimes = times => {
  // Get a random number that will indicate how many time slots we pick
  const timesToPick = getRandomNumInRange(0, times.length);

  // If the random picked is the maximum possible then return all times
  if (timesToPick === times.length - 1) {
    return times;
  }

  let timesPicked = [];

  // Loop until we have picked specified number of times
  while (timesToPick !== timesPicked.length - 1) {
    // Get a new index and time
    const index = getRandomNumInRange(0, times.length);
    const selectedTime = times[index];
    // If we already picked that time we continue
    // as we don't want duplicated
    if (timesPicked.includes(selectedTime)) continue;
    // Keep the time
    timesPicked.push(selectedTime);
  }

  // We need to sort the times, as they may not be in a correct order
  return timesPicked.sort();
};

const BookDrivingSlot = props => {
  const [bookingDate, setBookingDate] = useState(null);
  const [selectedTimeSlot, setSelectedTimeSlot] = useState(null);
  const [bookingTimes, setBookingTimes] = useState([]);
  const timeSlotCacheRef = useRef(new Map());

  useEffect(() => {
    // Bail out if there is no date selected
    if (!bookingDate) return;

    // Get time slots from cache
    let newBookingTimes = timeSlotCacheRef.current.get(
      bookingDate.toDateString()
    );

    // If we have no cached time slots then pick new ones
    if (!newBookingTimes) {
      newBookingTimes = pickSlotTimes(times);
      // Update cache with new time slots for the selected date
      timeSlotCacheRef.current.set(bookingDate.toDateString(), newBookingTimes);
    }

    setBookingTimes(newBookingTimes);
  }, [bookingDate]);

  const onDateChange = e => {
    setSelectedTimeSlot(null);
    setBookingDate(e.value);
  };

  return (
    <div className="k-my-8">
      <div className="k-mb-4 k-font-weight-bold">Book driving slot</div>

      <div className="k-flex k-display-flex k-mb-4">
        <Calendar value={bookingDate} onChange={onDateChange} />
        <div className="k-ml-4 k-display-flex k-flex-col">
          {bookingTimes.map(time => {
            return (
              <button
                key={time}
                className="k-button k-mb-4"
                onClick={e => setSelectedTimeSlot(time)}
              >
                {time}
              </button>
            );
          })}
        </div>
      </div>

      {bookingDate && selectedTimeSlot ? (
        <div>
          Selected slot: {bookingDate.toDateString()} at {selectedTimeSlot}
        </div>
      ) : null}
    </div>
  );
};

export default BookDrivingSlot;

Let’s digest the code we have in the BookDrivingSlot component. First, we define a list of possible time slots available for the day. These will be picked at random when a user selects a date in the calendar. The time slots would normally come from a database, but this will suffice for our example.

Next we have getRandomNumInRange and pickSlotTimes functions. The former is quite self-explanatory, as it returns a random number between the min and max passed. The latter does two things. First, it generates a random number that will indicate how many time slots we will have for the selected day. For example, if the generated number is 2, then there will be two time slots available for the day. If the number generated is the same as the amount of time slots in the times array, then the times array is returned.

// Get a random number that will indicate how many time slots we pick  
const timesToPick = getRandomNumInRange(0, times.length);  
  
// If the random picked is the maximum possible then return all times  
if (timesToPick === times.length - 1) {  
  return times;  
}  

Otherwise, it will loop until it finds the required number of time slots and then will return them sorted.

  let timesPicked = [];

  // Loop until we have picked specified number of times
  while (timesToPick !== timesPicked.length - 1) {
    // Get a new index and time
    const index = getRandomNumInRange(0, times.length);
    const selectedTime = times[index];
    // If we already picked that time we continue
    // as we don't want duplicated
    if (timesPicked.includes(selectedTime)) continue;
    // Keep the time
    timesPicked.push(selectedTime);
  }

  // We need to sort the times, as they may not be in a correct order
  return timesPicked.sort();

We have a few stateful values to store the selected date: available time slots and a selected time slot. Besides that, we have a timeSlotCacheRef that is used to cache time slots for selected dates, so we don’t have to recompute them multiple times.

The useEffect will run once when the component is mounted and then every time the booking date changes. If there is no booking date, we bail out. Otherwise, we get booking time slots from the cache or pick new ones at random and update the cache.

useEffect(() => {
  // Bail out if there is no date selected
  if (!bookingDate) return;

  // Get time slots from cache
  let newBookingTimes = timeSlotCacheRef.current.get(
    bookingDate.toDateString()
  );

  // If we have no cached time slots then pick new ones
  if (!newBookingTimes) {
    newBookingTimes = pickSlotTimes(times);
    // Update cache with new time slots for the selected date
    timeSlotCacheRef.current.set(bookingDate.toDateString(), newBookingTimes);
  }

  setBookingTimes(newBookingTimes);
}, [bookingDate]);

Finally, the component renders the calendar, buttons with available time slots, and the selected date and time.

Now, update the App.js file to include the BookDrivingSlot component.

src/App.js

import "@progress/kendo-theme-default/dist/all.css";
import "./App.css";
import PickDateOfBirth from "./components/calendar/PickDateOfBirth";
import BookDrivingSlot from "./components/calendar/BookDrivingSlot";

function App() {
  return (
    <div className="App">
      <PickDateOfBirth />
      <hr className="k-my-8" />
      <BookDrivingSlot />
    </div>
  );
}

export default App;

The gif below shows the functionality. As you can see, thanks to the KendoReact Calendar component, we can implement useful functionality quite easily.

Book driving slot: Once a date is selected, available time blocks appear to the right of the calendar. Changing the selected date changes the available time blocks.

A React calendar component is a good choice when you need to allow users to select a specific date. It can be used in conjunction with other components and elements to create richer and more complex functionality. Here we combined it with time slot buttons, but there are other use cases for it. For instance, it can be used together with input fields to create a date picker and date range picker. To see what else you can do with the Calendar component, you can check out its documentation.

React Scheduler

We have covered examples of using a React calendar component. Now, let’s explore using a React scheduler component. The Scheduler component offered by KendoReact, as the name suggests, allows users to schedule events. It offers a lot of useful functionality and can be used to create a variety of features. A good comparison is Google Calendar, which allows users to schedule tasks, events and reminders. Some other examples include event and booking management systems or work meeting schedules.

To showcase how the Scheduler can be used, we will implement a meeting room scheduler. Imagine a large office where there are a lot of employees, but only three meeting rooms. Employees should be able to reserve a room ahead of time to avoid collisions with others who would also want to meet and talk. Let’s start by creating the RoomScheduler component.

src/components/scheduler/RoomScheduler.js

import {
  Scheduler,
  TimelineView,
  DayView,
  WeekView,
  MonthView,
  AgendaView,
} from "@progress/kendo-react-scheduler";
import { useState } from "react";
import { guid } from "@progress/kendo-react-common";

const meetingRooms = {
  name: "Meeting Room",
  data: [
    {
      text: "Blue room",
      value: 1,
      color: "blue",
    },
    {
      text: "Red room",
      value: 2,
      color: "red",
    },
    {
      text: "Green room",
      value: 3,
      color: "green",
    },
  ],
  field: "RoomID",
  valueField: "value",
  textField: "text",
  colorField: "color",
};

const compareById = matchingItem => item => matchingItem.id === item.id;

const RoomScheduler = props => {
  const [data, setData] = useState([]);

  const onDataChange = ({ created, updated, deleted }) => {
    // Add a unique id to each new item
    const newItemsWithIds = created.map(item => ({
      ...item,
      id: guid(),
    }));

    setData(dataState =>
      dataState.reduce((acc, item) => {
        // Skip the item if it was deleted
        if (deleted.find(compareById(item))) return acc;
        // Push the updated item or current item
        acc.push(updated.find(compareById(item)) || item);
        return acc;
      }, newItemsWithIds)
    );
  };

  return (
    <div className="k-my-8">
      <div className="k-mb-4 k-font-weight-bold">Book a room</div>
      <Scheduler
        editable
        data={data}
        onDataChange={onDataChange}
        resources={[meetingRooms]}
      >
        <TimelineView />
        <DayView />
        <WeekView />
        <MonthView />
        <AgendaView />
      </Scheduler>
    </div>
  );
};

export default RoomScheduler;

First, we have defined the meetingRooms variable, which specified the details of rooms available in the office. Besides that, we could add more fields, such as whom the room was booked by, attendees and more, but just meeting rooms will do for this example.

The KendoReact Scheduler component offers five default views:

  • Timeline
  • Day
  • Week
  • Month
  • Agenda

There is no need to use all of them at once. We could just use the day, week and month views, or the other two.

Any time the data is changed by the user, the handler receives an object with properties, such as created, updated and deleted. These store items that were modified, so in the onDataChange handler, we add a unique ID for the items that were created, and then we update or delete the rest of the items where applicable.

Last but not least, add the RoomScheduler component in the App.js file.

src/App.js

import "@progress/kendo-theme-default/dist/all.css";
import "./App.css";
import PickDateOfBirth from "./components/calendar/PickDateOfBirth";
import BookDrivingSlot from "./components/calendar/BookDrivingSlot";
import RoomScheduler from "./components/scheduler/RoomScheduler";
function App() {
  return (
    <div className="App">
      <PickDateOfBirth />
      <hr className="k-my-8" />
      <BookDrivingSlot />
      <hr className="k-my-8" />
      <RoomScheduler />
    </div>
  );
}

export default App;

Below you can see the scheduler component in action.

Looking at a calendar, a user flips through timeline, day, week, month and agenda views. They clicked to make an event  and specify which of the three rooms to use. The different rooms each have their own color on the calendar, so it's easy to tell at a glance when each room is reserved,

There are many more features available than what’s showcased in this simple example, so definitely check out the KendoReact Scheduler documentation.

Wrap-up

There we have it. We have covered basic differences between a React calendar and a React scheduler component. As you have seen, the React calendar component can be used to implement features that allow users to select specific dates. On the other hand, the React scheduler is a good choice for meeting scheduling or agenda-like applications.

If you’re adding such components to your own app, I recommend checking out using third-party components. It’s not an easy feat to implement well-working calendar and scheduler components, so using ready-made solutions like the ones found in KendoReact is a good idea, as you get nice-looking and feature-rich components out of the box. What’s more, both components provide support for dealing with time zones, localization and internationalization, so they can save you a lot of time and effort.


Thomas Findlay-2
About the Author

Thomas Findlay

Thomas Findlay is a 5-star rated mentor, full-stack developer, consultant, technical writer and the author of “React - The Road To Enterprise” and “Vue - The Road To Enterprise.” He works with many different technologies such as JavaScript, Vue, React, React Native, Node.js, Python, PHP and more. Thomas has worked with developers and teams from beginner to advanced and helped them build and scale their applications and products. Check out his Codementor page, and you can also find him on Twitter.

Related Posts

Comments

Comments are disabled in preview mode.