Skip to content

Instantly share code, notes, and snippets.

@Sivamani-18
Last active April 29, 2024 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sivamani-18/cbf763b6320364e0163729a0b362c31f to your computer and use it in GitHub Desktop.
Save Sivamani-18/cbf763b6320364e0163729a0b362c31f to your computer and use it in GitHub Desktop.
React Calendar Component

React Multi Calendar & Date Picker

A simple and accessible React Calendar & Date Picker component that allows users to select dates. The component supports single date selection by default and can be configured for multi-date selection.

Click Demo

Click LIBRARY

screenshot-localhost_3000-2023 08 10-14_27_43

Installation

To install the package, you can use npm:

npm install react-multi-date-picker-calendar

Usage

Here's how you can use the Calendar & Date Picker component in your React application:

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
  const handleDateChange = (dates) => {
    // Handle the selected dates
    console.log("Selected Dates:", dates);
  };

  return (
    <div>
      <h1>My App</h1>
      <Calendar
        multiSelect={true}
        // dates={[new Date("2023-07-18T05:45:48.005Z")]}

        onChange={handleDateChange} />
    </div>
  );
};

export default App;

Calendar Component

A versatile date picker React component that supports various selection modes and features.

Props

The Calendar component accepts the following props:

Prop Type Default Description
multiSelect boolean false Enable multi-date selection.
dates Date[] [] An array of pre-selected dates.
label string - Label for the date picker input.
id string Auto-generated ID for the date picker input.
readonly boolean true Whether the input field is readonly.
isDisabled boolean false Whether the date picker is disabled.
onChange function - Callback function when selected dates change.
minDate Date - Minimum selectable date.
maxDate Date - Maximum selectable date.
disabledDates Date[] [] An array of disabled dates.
selectsRange boolean false Enable date range selection.
PrevIcon React.ReactNode - Custom icon for the previous button.
NextIcon React.ReactNode - Custom icon for the next button.
showMonth boolean false Show month dropdown for navigation.
showYear boolean false Show year dropdown for navigation.
minYear number 1970 Minimum year in the year dropdown.
maxYear number 2025 Maximum year in the year dropdown.
appointments Appointment[] [] An array of appointments to display with status.
showSelectedDatesList boolean false Show a list of selected dates.
showDatePicker boolean false Show the date picker input.
tooltipVisible boolean false Show the tooltip.

Interface: Appointment

Property Type Description
date Date The date of the appointment.
status string The status of the appointment (e.g., 'Missed', 'Cancelled', 'Incomplete', 'Completed', etc.).
id string (Optional) Unique ID for the appointment.
time string (Optional) The time of the appointment.
title string (Optional) The title of the appointment.

Examples

Single Date Selection

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
  const handleDateChange = (dates) => {
    console.log("Selected Dates:", dates);
  };

  return <Calendar onChange={handleDateChange} />;
};

export default App;

Multi-Date Selection

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
  const handleDateChange = (dates) => {
    console.log("Selected Dates:", dates);
  };

  return <Calendar multiSelect onChange={handleDateChange} />;
};

export default App;

Date Range Selection

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
  const handleDateChange = (dates) => {
    console.log("Selected Dates:", dates);
  };

  return <Calendar selectsRange onChange={handleDateChange} />;
};

export default App;

Specific Dates Disabled

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
const disabledDates: Date[] = [
    new Date("2023-07-12"), // Example: Disable July 5th, 2023
    new Date("2023-07-16"),
    new Date("2023-07-18"),
    new Date("2023-07-20"),
    new Date("2023-07-22"),
    new Date("2023-07-25")
    // Add more Date objects as needed for other disabled dates
  ];
  
  const handleDateChange = (dates) => {
    console.log("Selected Dates:", dates);
  };

  return  <Calendar disabledDates={disabledDates} onChange={handleDateChange} />;
};

export default App;

Min & Max Date Picker

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
  const handleDateChange = (dates) => {
    console.log("Selected Dates:", dates);
  };

  return  <Calendar 
          disabledDates={disabledDates} 
          onChange={handleDateChange}  
          minDate={new Date()}
          maxDate={new Date("2024-07-25")} />;
};

export default App;

Selected Dates List

import React from "react";
import Calendar from "react-multi-date-picker-calendar";

const App = () => {
  const handleDateChange = (dates) => {
    console.log("Selected Dates:", dates);
  };

  return  <Calendar
            multiSelect={true}
            showSelectedDatesList
            onChange={handleDateChange}
          />;
};

export default App;

Appointment Status

import React from "react";
import Calendar, {
  logSelectedDatesAppointments,
  Appointment
} from "react-multi-date-picker-calendar";

const App = () => {
    const appointments: Appointment[] = [
    {
      date: new Date('2023-08-10'),
      status: 'Completed',
      id: '123',
      time: '10:00 AM',
      title: 'Meeting with Client A',
    },
    {
      date: new Date('2023-08-10'),
      status: 'Completed',
      id: '456',
      time: '2:30 PM',
      title: 'Meeting with Client B',
    },
    {
      date: new Date('2023-08-10'),
      status: 'Completed',
      id: '457',
      time: '2:30 PM',
      title: 'Meeting with Client B',
    },
    {
      date: new Date('2023-08-10'),
      status: 'incomplete',
    },
    {
      date: new Date('2023-08-11'),
      status: 'completed',
    },
    {
      date: new Date('2023-08-11'),
      status: 'Cancelled',
    },
    {
      date: new Date('2023-08-13'),
      status: 'Missed',
    },
    {
      date: new Date('2023-08-13'),
      status: 'incomplete',
    },
    {
      date: new Date('2023-08-15'),
      status: 'Cancelled',
    },
    {
      date: new Date('2023-08-15'),
      status: 'Missed',
    },
    // Add more appointments as needed...
  ];

  // Define the handleSelectedDatesChange function (same as before)
  const handleSelectedDatesChange = (selectedDates: Date[]) => {
    const selectedAppointments = logSelectedDatesAppointments(
      selectedDates,
      appointments
    );
    console.log("Selected Dates:", selectedDates);
    console.log("Selected Dates Appointments:", selectedAppointments);
    // Add any other logic you want to perform when selected dates change
  };

  return   <Calendar
        onChange={handleSelectedDatesChange}
        multiSelect={true}
        PrevIcon="<<"
        NextIcon=">>"
        showMonth={true}
        showYear={true}
        appointments={appointments}
      />;
};

export default App;

Method: logSelectedDatesAppointments

  const handleSelectedDatesChange = (selectedDates: Date[]) => {
    const selectedAppointments = logSelectedDatesAppointments(
      selectedDates,
      appointments
    );
    console.log('Selected Dates Appointments:', selectedAppointments);
  };

Customization

You can customize the appearance and behavior of the calendar component by passing different props. Additionally, you can style the component using CSS.

CSS

.calendar-section {
  position: relative;
  display: inline-block;
}

.calendar-container.open-calendar-popup {
  position: absolute;
  right: 0;
  left: 0;
  width: max-content;
  z-index: 99999;
}
.calendar-container.close-calendar-popup {
  display: none;
}
.calendar-container.open-calendar-popup.calendar-top {
  bottom: calc(
    100% + 10px
  ); /* Adjust the value as needed to position the calendar */
}

.calendar-container.open-calendar-popup.calendar-bottom {
  top: calc(
    100% + 10px
  ); /* Adjust the value as needed to position the calendar */
}
.calendar-container {
  min-height: 320px;
  font-family: Arial, sans-serif;
  display: inline-flex;
  background-color: #fff;
  border: 1px solid #e0e0e0;
}

.calendar-input-group {
  display: block;
  text-align: left;
}

.calendar-input-group label {
  margin-bottom: 8px;
  display: inline-block;
}

.input-container {
  display: flex;
  align-items: center;
  position: relative;
}

.calendar-input {
  width: 100%;
  min-height: 35px;
}

.icon-container {
  display: inline-block;
  width: 24px; /* Adjust dimensions as needed */
  height: 24px;
  position: absolute;
  top: 50%;
  right: 5px; /* Adjust as needed */
  transform: translateY(-50%);
  pointer-events: none;
}

.calendar-section {
  width: 300px;
  margin: 0 auto;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: #f0f0f0;
  min-height: 56px;
}

.calendar-btn {
  background-color: transparent;
  border: none;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
}

.calendar-month {
  margin: 0;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}

.calendar-day {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 40px;
  background-color: #fff;
  border: 1px solid #e0e0e0;
  cursor: pointer;
}

.calendar-day.empty {
  background-color: #f0f0f0;
  cursor: default;
}

.calendar-day.today {
  background-color: #e0e0e0;
  font-weight: bold;
}

.calendar-day:focus {
  outline: 2px solid #007bff;
}

.calendar-day.selected {
  background-color: #007bff;
  color: #fff;
}

.calendar-day.selected:hover {
  background-color: #0069d9;
}

.calendar-weekdays {
  justify-content: space-between;
  background-color: #f0f0f0;
  padding: 8px 0;
  font-weight: bold;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}

.calendar-weekday {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 25px;
  background-color: #f0f0f0;
}

/* CSS */
/* Styles for the dropdown container */
.calendar-dropdown-container {
  position: relative;
  display: inline-block;
  margin: 0 5px;
}

/* Styles for the dropdown button */
.calendar-month-button {
  min-width: 100px;
  padding: 5px 5px 5px 10px;
  border: 1px solid #ccc;
  background-color: #f9f9f9;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.monthDropdown-close {
  display: none;
}

.yearDropdown-close {
  display: none;
}

/* Styles for the dropdown options list */
.calendar-month-list {
  min-width: 72px;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1;
  list-style: none;
  padding: 0;
  margin: 0;
  border: 1px solid #ccc;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  max-height: 255px;
  overflow: auto;
}

/* Styles for the individual dropdown option */
.calendar-month-option {
  padding: 8px;
  cursor: pointer;
  font-size: 14px;
}

/* Styles for the dropdown button */
.calendar-year-button {
  min-width: 75px;
  padding: 5px 5px 5px 10px;
  border: 1px solid #ccc;
  background-color: #f9f9f9;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Styles for the dropdown options list */
.calendar-year-list {
  min-width: 72px;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1;
  list-style: none;
  padding: 0;
  margin: 0;
  border: 1px solid #ccc;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  max-height: 255px;
  overflow: auto;
}

/* Styles for the individual dropdown option */
.calendar-year-option {
  padding: 8px;
  cursor: pointer;
  font-size: 14px;
}

/* Styles for day dots container */
.calendar-day-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 5px;
  position: absolute;
  bottom: 2px;
  left: 0;
  right: 0;
}

/* Styles for individual dots */
.calendar-day-dots .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin: 0 2px;
}

/* Styles for different appointment statuses */
.dot-missed {
  background-color: red;
}

.dot-cancelled {
  background-color: orange;
}

.dot-incomplete {
  background-color: yellow;
}

.dot-completed {
  background-color: green;
}

/* Style for the "more" dot */
.dot-more {
  font-size: 10px;
  margin-left: 2px;
}

/* CSS for the selected dates list */
.selected-dates-list {
  min-width: 120px;
  flex: 1 1;
  padding: 10px;
  border-left: 1px solid #ccc;
  list-style: none;
  margin: 0;
  min-height: 255px;
  max-height: 299px;
  overflow: auto;
  overflow-x: hidden;
  height: calc(100% - 65px);
}

.selected-list-block {
  border-left: 1px solid #ccc;
  border-bottom: 1px solid #ccc;
  padding: 13px 20px;
}

.selected-list-block p {
  margin: auto;
  font-weight: bold;
}

.selected-dates-list li {
  margin-bottom: 5px;
  display: flex;
  align-items: center;
}

/* CSS for the close button */
.close-button {
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  margin-left: 5px;
  color: #888;
}

.close-button:hover {
  color: #f00; /* Change the color when hovered for better visibility */
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* CSS for the tooltip */
.tooltip {
  position: absolute;
  background-color: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 10px;
  border-radius: 5px;
  font-size: 14px;
  display: block;
  z-index: 99999;
  width: max-content;
}

.tooltip .tooltip_info {
  margin: 0;
}

.tooltip-dot {
  display: inline-flex;
  flex-shrink: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin: 0 2px;
}

.tooltip-list {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}
.tooltip-list:last-child {
  margin-bottom: 0;
}
.tooltip-dot {
  margin-right: 4px;
}

Accessibility

The Calendar component is designed with accessibility in mind. It includes ARIA attributes for improved screen reader support and supports keyboard navigation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment