---
title: "Javascript Range Rental Availability Example | Mobiscroll"
component: "Range"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/range/book-rental-months-ahead"
---

# Rental Availability - JavaScript Range demo

Build a vacation rental availability calendar with the Javascript date range picker — multi-month view with automatic booking validation. Plain JS api for usage everywhere.

- [Live demo](https://demo.mobiscroll.com/javascript/range/book-rental-months-ahead)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-javascript/tree/main/src/demos/datepicker/range/book-rental-months-ahead)
- This demo in other frameworks: [jQuery](https://demo.mobiscroll.com/jquery/range/book-rental-months-ahead.md), [Angular](https://demo.mobiscroll.com/angular/range/book-rental-months-ahead.md), [React](https://demo.mobiscroll.com/react/range/book-rental-months-ahead.md), [Vue](https://demo.mobiscroll.com/vue/range/book-rental-months-ahead.md)

## Description

Use the multiple month view of the date picker for building an availability calendar for a vacation rental. The [colored backgrounds and labels](https://demo.mobiscroll.com/javascript/range/dots-colors-labels) can be used to display season and pricing information and [half-day styling](https://demo.mobiscroll.com/javascript/range/half-day-styling) to show check-in and check-out dates.

Booked dates are [disabled](https://demo.mobiscroll.com/javascript/range/disabled-invalid-values) and validation on check-in and check-out dates is automatic based on the data as a range for a new booking is applied.

## What this demo shows

- Displays availability across six consecutive months in a multi-month range booking calendar.
- **Seasonal pricing** Uses distinct date-cell backgrounds to identify pre-season, in-season, and off-season pricing periods.
- **Daily rates** Shows the price inside each available date cell for at-a-glance rate comparison.
- **Booked dates** Displays existing bookings in the calendar and distinguishes them from available dates.
- **Range selection** Highlights the check-in and check-out dates and the selected period between them.
- **Availability validation** Prevents users from selecting a range that conflicts with an existing booking.
- **Unavailable dates** Uses subdued styling for disabled dates while keeping the surrounding pricing and availability context visible.
- **Navigation** Supports moving between calendar periods and returning to the current date with the Today action.

## Best for

- **Accommodation booking** Showing long-term availability and seasonal rates for hotels, apartments, and other lodging.
- **Vacation rentals** Comparing daily prices and selecting stays around existing bookings.
- **Vehicle rentals** Presenting availability and rates across an extended booking window.
- **Seasonal pricing** Communicating rate changes across pre-season, in-season, and off-season periods.
- **Availability-based reservations** Preventing range selections that overlap unavailable or booked dates.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-themeVariant) - option
- [`controls`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-controls) - option
- [`select`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-select) - option
- [`display`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-display) - option
- [`calendarType`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-calendarType) - option
- [`calendarSize`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-calendarSize) - option
- [`min`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-min) - option
- [`showRangeLabels`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-showRangeLabels) - option
- [`inRangeInvalid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-inRangeInvalid) - option
- [`rangeEndInvalid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-rangeEndInvalid) - option
- [`renderCalendarHeader`](https://mobiscroll.com/docs/javascript/datepicker/api#renderer-renderCalendarHeader) - renderer
- [`setOptions`](https://mobiscroll.com/docs/javascript/datepicker/api#method-setOptions) - method
- [`labels`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-labels) - option
- [`invalid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-invalid) - option
- [`colors`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-colors) - option

## Code

### JS

```js
mobiscroll.setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

var formatDate = mobiscroll.formatDate;
var now = new Date();
var 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: '#b2f1c080',
    start: '2026-10-01T00:00',
    end: '2026-10-31T23:59',
    cellCssClass: 'md-book-rental-bg-off',
    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,
    },
  },
];
var myCalendar = mobiscroll.datepicker('#demo-book-rental-months-ahead', {
  controls: ['calendar'],
  select: 'range',
  display: 'inline',
  calendarType: 'month',
  calendarSize: 6,
  min: '2026-10-20T00:00',
  showRangeLabels: false,
  inRangeInvalid: false,
  rangeEndInvalid: true,
  renderCalendarHeader: function () {
    return (
      '<div mbsc-calendar-nav></div>' +
      '<div class="md-book-rental-header">' +
      '<div class="md-book-rental-zone md-book-rental-pre">pre-season</div>' +
      '<div class="md-book-rental-zone md-book-rental-in">in-season</div>' +
      '<div class="md-book-rental-zone md-book-rental-off">off-season</div>' +
      '<div class="md-book-rental-zone md-book-rental-booked">booked</div>' +
      '<div mbsc-calendar-prev></div>' +
      '<div mbsc-calendar-today></div>' +
      '<div mbsc-calendar-next></div>' +
      '</div>'
    );
  },
});

function getColors(start, end) {
  return [
    {
      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',
    },
  ];
}

mobiscroll.getJson(
  'https://trial.mobiscroll.com/getrentals/?year=' + now.getFullYear() + '&month=' + now.getMonth(),
  function (data) {
    var prices = data.prices;
    var bookings = data.bookings;
    var labels = [];
    var invalids = [];
    var colors = [];
    var endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0);

    for (var i = 0; i < prices.length; ++i) {
      var price = prices[i];
      var booked = bookings.find(function (b) {
        return formatDate('YYYY-M-D', new Date(b.checkIn)) === price.date;
      });
      if (booked) {
        var checkIn = new Date(booked.checkIn);
        var checkOut = new Date(booked.checkOut);
        var newCheckOut = new Date(checkOut.getFullYear(), checkOut.getMonth(), checkOut.getDate() - 1);
        colors = colors.concat(getColors(checkIn, checkOut));
        labels.push({
          start: checkIn,
          end: newCheckOut,
          text: 'booked',
          textColor: '#888',
        });
        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,
        });
      }
    }
    myCalendar.setOptions({ labels: labels, invalid: invalids, colors: colors.concat(monthColors) });
  },
  'jsonp',
);
```

### HTML

```html
<div id="demo-book-rental-months-ahead" class="md-book-rental"></div>
```

### CSS

```css
.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;
}
```

## Implementation notes

- Set `select: 'range'`, `controls: ['calendar']`, `display: 'inline'`, `calendarType: 'month'`, and `calendarSize: 6` on `Datepicker` to render six consecutive months of an inline range calendar.
- `min` restricts selection to today or later (e.g. `min: <today's date>`).
- Seasonal/pricing backgrounds are supplied through the `colors` option as an array of `{ background, cellCssClass, start, end, recurring: { repeat: 'yearly', month, day } }` entries - one entry per season block (pre-season, in-season, off-season), each with its own CSS background color and cell class, recurring yearly.
- Daily rates are shown via the `labels` option as an array of `{ date, text, textColor }` (or `{ start, end, text, textColor }` for a booked span) entries, one per date/range, rendering the price or "booked" text inside each cell.
- Existing bookings are excluded from selection through `invalid`, passed as an array of `{ start, end }` date-range objects matching each booking's check-in/check-out span.
- `inRangeInvalid: false` (default) still allows a selected range's endpoints to land next to invalid dates while blocking overlap with them; `rangeEndInvalid: true` additionally disallows the invalid start/end boundary dates themselves from being chosen as range endpoints.
- The calendar header (season legend plus nav/prev/next controls) is a custom renderer: React uses the `renderCalendarHeader` prop (returning JSX with `CalendarNav`, `CalendarPrev`, `CalendarToday`, `CalendarNext`); Angular uses `[calendarHeaderTemplate]` bound to an `ng-template` containing `mbsc-calendar-nav`/`mbsc-calendar-prev`/`mbsc-calendar-next`; Vue uses the `#header` named slot on `MbscDatepicker` containing `MbscCalendarNav`/`MbscCalendarPrev`/`MbscCalendarNext`.

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-javascript.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config javascript
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config javascript --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/javascript/getting-started/installation

## Related demos

- Previous: [Flight Booking](https://demo.mobiscroll.com/javascript/range/flight-booking.md) - Build a flight booking date picker with the Javascript range component — round-trip and one-way selection.
- Next: [Range Picker for Event Creation](https://demo.mobiscroll.com/javascript/range/adding-event-start-end.md) - Add a date range picker to event creation forms — switch between date-only and date+time modes with an all-day toggle for start and end date selection.
