React Range Rental Availability
Get started with this exampleUsage
theme="ios" You can turn auto theming on and let it decide based on the platform.
Usage
themeVariant="light" You can turn auto dark mode on based on system settings.
Usage
touchUi={true}
// touch interaction is enabled Use touch interaction on mobile or pointer interaction on desktop.
Usage
locale={localeEn} Selecting the locale loads the localized settings and the translated UI text.
Rental Availability
Use the multiple month view of the date picker for building an availability calendar for a vacation rental. The colored backgrounds and labels can be used to display season and pricing information and half-day styling to show check-in and check-out dates.
Booked dates are disabled and validation on check-in and check-out dates is automatic based on the data as a range for a new booking is applied.
Demo
Code
View code on GitHub
import {
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Datepicker,
formatDate,
getJson,
setOptions ,
} from '@mobiscroll/react';
import { useCallback, useEffect, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const now = new Date();
function App() {
const [labels, setLabels] = useState([]);
const [invalid, setInvalid] = useState([]);
const [colors, setColors] = useState([]);
const getColors = useCallback(
(start, end) => [
{
date: start,
cellCssClass: 'vacation-check-in',
},
{
date: end,
cellCssClass: 'vacation-check-out',
},
{
start: new Date(start.getFullYear(), start.getMonth(), start.getDate() + 1),
end: new Date(end.getFullYear(), end.getMonth(), end.getDate() - 1),
background: '#ffbaba80',
cellCssClass: 'vacation-booked',
},
],
[],
);
const calendarHeader = useCallback(
() => (
<>
<CalendarNav />
<div className="md-book-rental-header">
<div className="md-book-rental-zone md-book-rental-pre">pre-season</div>
<div className="md-book-rental-zone md-book-rental-in">in-season</div>
<div className="md-book-rental-zone md-book-rental-off">off-season</div>
<div className="md-book-rental-zone md-book-rental-booked">booked</div>
</div>
<CalendarPrev />
<CalendarToday />
<CalendarNext />
</>
),
[],
);
useEffect(() => {
const monthColors = [
{
background: '#b2f1c080',
start: '2026-01-01T00:00',
end: '2026-01-31T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 1,
day: 1,
},
},
{
background: '#b2f1c080',
start: '2026-02-01T00:00',
end: '2026-02-28T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 2,
day: 1,
},
},
{
background: '#b2f1c080',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 2,
day: 29,
},
},
{
background: '#a3cdff80',
start: '2026-03-01T00:00',
end: '2026-03-31T23:59',
cellCssClass: 'md-book-rental-bg-pre',
recurring: {
repeat: 'yearly',
month: 3,
day: 1,
},
},
{
background: '#a3cdff80',
start: '2026-04-01T00:00',
end: '2026-04-30T00:00',
cellCssClass: 'md-book-rental-bg-pre',
recurring: {
repeat: 'yearly',
month: 4,
day: 1,
},
},
{
background: '#a3cdff80',
start: '2026-05-01T00:00',
end: '2026-05-31T00:00',
cellCssClass: 'md-book-rental-bg-pre',
recurring: {
repeat: 'yearly',
month: 5,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-06-01T00:00',
end: '2026-06-30T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 6,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-07-01T00:00',
end: '2026-07-31T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 7,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-08-01T00:00',
end: '2026-08-31T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 8,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-09-01T00:00',
end: '2026-09-30T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 9,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-10-01T00:00',
end: '2026-10-31T23:59',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 10,
day: 1,
},
},
{
background: '#b2f1c080',
start: '2026-11-01T00:00',
end: '2026-11-30T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 11,
day: 1,
},
},
{
background: '#b2f1c080',
start: '2026-12-01T00:00',
end: '2026-12-31T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 12,
day: 1,
},
},
];
getJson(
'https://trial.mobiscroll.com/getrentals/?year=' + now.getFullYear() + '&month=' + now.getMonth(),
(data) => {
const prices = data.prices;
const bookings = data.bookings;
let labels = [];
let invalids = [];
let colors = [];
let endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0);
for (let i = 0; i < prices.length; ++i) {
const price = prices[i];
const booked = bookings.find((b) => formatDate('YYYY-M-D', new Date(b.checkIn)) === price.date);
if (booked) {
const checkIn = new Date(booked.checkIn);
const checkOut = new Date(booked.checkOut);
const newCheckOut = new Date(checkOut.getFullYear(), checkOut.getMonth(), checkOut.getDate() - 1);
colors = [...colors, ...getColors(checkIn, checkOut)];
labels.push({
start: checkIn,
end: newCheckOut,
text: 'booked',
textColor: '#1e1e1ecc',
});
invalids.push({
start: checkIn,
end: newCheckOut,
});
endDate = checkOut;
} else if (new Date(price.date) >= endDate) {
labels.push({
date: new Date(price.date),
text: price.text,
textColor: price.textColor,
});
}
}
setLabels(labels);
setInvalid(invalids);
setColors([...colors, ...monthColors]);
},
'jsonp',
);
}, [getColors]);
return (
<Datepicker
cssClass="md-book-rental"
controls={['calendar']}
select="range"
display="inline"
calendarType="month"
calendarSize={6}
min={'2026-11-09T00:00'}
showRangeLabels={false}
inRangeInvalid={false}
rangeEndInvalid={true}
renderCalendarHeader={calendarHeader}
labels={labels}
invalid={invalid}
colors={colors}
/>
);
}
export default App;
import {
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Datepicker,
formatDate,
getJson,
MbscCalendarColor,
MbscCalendarLabel,
setOptions ,
} from '@mobiscroll/react';
import { FC, useCallback, useEffect, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const now = new Date();
const App: FC = () => {
const [labels, setLabels] = useState<MbscCalendarLabel[]>([]);
const [invalid, setInvalid] = useState([]);
const [colors, setColors] = useState<MbscCalendarColor[]>([]);
const getColors = useCallback(
(start: Date, end: Date) => [
{
date: start,
cellCssClass: 'vacation-check-in',
},
{
date: end,
cellCssClass: 'vacation-check-out',
},
{
start: new Date(start.getFullYear(), start.getMonth(), start.getDate() + 1),
end: new Date(end.getFullYear(), end.getMonth(), end.getDate() - 1),
background: '#ffbaba80',
cellCssClass: 'vacation-booked',
},
],
[],
);
const calendarHeader = useCallback(
() => (
<>
<CalendarNav />
<div className="md-book-rental-header">
<div className="md-book-rental-zone md-book-rental-pre">pre-season</div>
<div className="md-book-rental-zone md-book-rental-in">in-season</div>
<div className="md-book-rental-zone md-book-rental-off">off-season</div>
<div className="md-book-rental-zone md-book-rental-booked">booked</div>
</div>
<CalendarPrev />
<CalendarToday />
<CalendarNext />
</>
),
[],
);
useEffect(() => {
const monthColors: MbscCalendarColor[] = [
{
background: '#b2f1c080',
start: '2026-01-01T00:00',
end: '2026-01-31T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 1,
day: 1,
},
},
{
background: '#b2f1c080',
start: '2026-02-01T00:00',
end: '2026-02-28T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 2,
day: 1,
},
},
{
background: '#b2f1c080',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 2,
day: 29,
},
},
{
background: '#a3cdff80',
start: '2026-03-01T00:00',
end: '2026-03-31T23:59',
cellCssClass: 'md-book-rental-bg-pre',
recurring: {
repeat: 'yearly',
month: 3,
day: 1,
},
},
{
background: '#a3cdff80',
start: '2026-04-01T00:00',
end: '2026-04-30T00:00',
cellCssClass: 'md-book-rental-bg-pre',
recurring: {
repeat: 'yearly',
month: 4,
day: 1,
},
},
{
background: '#a3cdff80',
start: '2026-05-01T00:00',
end: '2026-05-31T00:00',
cellCssClass: 'md-book-rental-bg-pre',
recurring: {
repeat: 'yearly',
month: 5,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-06-01T00:00',
end: '2026-06-30T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 6,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-07-01T00:00',
end: '2026-07-31T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 7,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-08-01T00:00',
end: '2026-08-31T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 8,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-09-01T00:00',
end: '2026-09-30T00:00',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 9,
day: 1,
},
},
{
background: '#f7f7bb80',
start: '2026-10-01T00:00',
end: '2026-10-31T23:59',
cellCssClass: 'md-book-rental-bg-in',
recurring: {
repeat: 'yearly',
month: 10,
day: 1,
},
},
{
background: '#b2f1c080',
start: '2026-11-01T00:00',
end: '2026-11-30T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 11,
day: 1,
},
},
{
background: '#b2f1c080',
start: '2026-12-01T00:00',
end: '2026-12-31T00:00',
cellCssClass: 'md-book-rental-bg-off',
recurring: {
repeat: 'yearly',
month: 12,
day: 1,
},
},
];
getJson(
'https://trial.mobiscroll.com/getrentals/?year=' + now.getFullYear() + '&month=' + now.getMonth(),
(data) => {
const prices = data.prices;
const bookings = data.bookings;
const labels: Array<MbscCalendarLabel> = [];
const invalids: Array<object> = [];
let colors: Array<MbscCalendarColor> = [];
let endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0);
for (let i = 0; i < prices.length; ++i) {
const price = prices[i];
const booked = bookings.find((b: { checkIn: string }) => formatDate('YYYY-M-D', new Date(b.checkIn)) === price.date);
if (booked) {
const checkIn = new Date(booked.checkIn);
const checkOut = new Date(booked.checkOut);
const newCheckOut = new Date(checkOut.getFullYear(), checkOut.getMonth(), checkOut.getDate() - 1);
colors = [...colors, ...getColors(checkIn, checkOut)];
labels.push({
start: checkIn,
end: newCheckOut,
text: 'booked',
textColor: '#1e1e1ecc',
});
invalids.push({
start: checkIn,
end: newCheckOut,
});
endDate = checkOut;
} else if (new Date(price.date) >= endDate) {
labels.push({
date: new Date(price.date),
text: price.text,
textColor: price.textColor,
});
}
}
setLabels(labels);
setInvalid(invalid);
setColors([...colors, ...monthColors]);
},
'jsonp',
);
}, [getColors, invalid]);
return (
<Datepicker
cssClass="md-book-rental"
controls={['calendar']}
select="range"
display="inline"
calendarType="month"
calendarSize={6}
min={'2026-11-09T00:00'}
showRangeLabels={false}
inRangeInvalid={false}
rangeEndInvalid={true}
renderCalendarHeader={calendarHeader}
labels={labels}
invalid={invalid}
colors={colors}
/>
);
};
export default App;
.mbsc-datepicker .md-book-rental-bg-off.vacation-check-in.mbsc-ltr {
background: linear-gradient(to left top, #ffbaba80 50%, #b2f1c080 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-pre.vacation-check-in.mbsc-ltr {
background: linear-gradient(to left top, #ffbaba80 50%, #a3cdff80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-in.vacation-check-in.mbsc-ltr {
background: linear-gradient(to left top, #ffbaba80 50%, #f7f7bb80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-off.vacation-check-out.mbsc-ltr {
background: linear-gradient(to left top, #b2f1c080 50%, #ffbaba80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-pre.vacation-check-out.mbsc-ltr {
background: linear-gradient(to left top, #a3cdff80 50%, #ffbaba80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-in.vacation-check-out.mbsc-ltr {
background: linear-gradient(to left top, #f7f7bb80 50%, #ffbaba80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-off.vacation-check-in.mbsc-rtl {
background: linear-gradient(to right bottom, #ffbaba80 50%, #b2f1c080 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-pre.vacation-check-in.mbsc-rtl {
background: linear-gradient(to right bottom, #ffbaba80 50%, #a3cdff80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-in.vacation-check-in.mbsc-rtl {
background: linear-gradient(to right bottom, #ffbaba80 50%, #f7f7bb80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-off.vacation-check-out.mbsc-rtl {
background: linear-gradient(to right bottom, #b2f1c080 50%, #ffbaba80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-pre.vacation-check-out.mbsc-rtl {
background: linear-gradient(to right bottom, #a3cdff80 50%, #ffbaba80 50%) no-repeat;
}
.mbsc-datepicker .md-book-rental-bg-in.vacation-check-out.mbsc-rtl {
background: linear-gradient(to right bottom, #f7f7bb80 50%, #ffbaba80 50%) no-repeat;
}
.mbsc-datepicker .vacation-check-out,
.mbsc-datepicker .vacation-check-in {
color: initial;
}
.mbsc-datepicker .vacation-check-in.mbsc-calendar-cell.mbsc-calendar-day-empty,
.mbsc-datepicker .vacation-check-out.mbsc-calendar-cell.mbsc-calendar-day-empty {
background: transparent;
}
.md-book-rental-header {
display: flex;
align-items: center;
justify-content: end;
margin-left: auto;
flex: 1 1;
overflow: hidden;
}
.md-book-rental-zone {
font-size: 12px;
padding: 3px 6px;
margin: 0 5px;
border-radius: 16px;
color: #1e1e1ecc;
}
.md-book-rental .mbsc-calendar-label-text {
text-align: center;
font-weight: bold;
}
.md-book-rental-in {
background: #f7f7bb80;
}
.md-book-rental-pre {
background: #a3cdff80;
}
.md-book-rental-off {
background: #b2f1c080;
}
.md-book-rental-booked {
background: #ffbaba80;
}