Availability & Booking Calendar
Build appointment booking and availability calendars with custom modifier styles, disabled dates, and month change loading indicators.
Availability & Booking Calendar
Create availability calendars for appointments, hotel bookings, or resource scheduling using disabled dates, custom modifier classes, and async month navigation callbacks.
Live Preview: Availability & Booking Calendar
SUN
MON
TUE
WED
THU
FRI
SAT
Code Example
import { useState } from 'react';
import { Calendar } from 'react-modular-datepicker';
import 'react-modular-datepicker/dist/index.css';
const getRandomDatesInMonth = (year: number, month: number) => {
const totalDaysInMonth = new Date(year, month + 1, 0).getDate();
const count = Math.floor(Math.random() * 6) + 5;
const randomDayNumbers = new Set<number>();
while (randomDayNumbers.size < Math.min(count, totalDaysInMonth)) {
randomDayNumbers.add(Math.floor(Math.random() * totalDaysInMonth) + 1);
}
return Array.from(randomDayNumbers).map((day) => new Date(year, month, day));
};
export function AvailabilityExample() {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth();
const [bookedDays, setBookedDays] = useState(
getRandomDatesInMonth(year, month)
);
const [selectedDate, setSelectedDate] = useState<Date | null>(
new Date(year, month, 8)
);
const [isLoading, setIsLoading] = useState(false);
const handleMonthChange = (dates: Date[]) => {
setIsLoading(true);
setTimeout(() => {
const firstDate = dates[0] || new Date();
const targetYear = firstDate.getFullYear();
const targetMonth = firstDate.getMonth();
setBookedDays(getRandomDatesInMonth(targetYear, targetMonth));
setIsLoading(false);
}, 700);
};
return (
<div className="relative inline-block">
<Calendar
selected={selectedDate || undefined}
onChange={(d) => setSelectedDate(d as Date)}
onMonthChange={handleMonthChange}
disabledDates={bookedDays}
classNames={{
day: {
disabled: 'text-red-400 line-through cursor-not-allowed',
},
}}
/>
{isLoading && (
<div className="absolute inset-0 bg-white/80 backdrop-blur-xs flex flex-col items-center justify-center rounded-lg z-20">
<div className="w-7 h-7 border-3 border-[#c5a059] border-t-transparent rounded-full animate-spin mb-2" />
<span className="text-xs font-semibold text-gray-700">Fetching availabilities...</span>
</div>
)}
</div>
);
}