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

# Rental Availability - Angular Range demo

Build a vacation rental availability calendar with the Angular date range picker — multi-month view with automatic booking validation. For Angular 22 and Ionic 8.

- [Live demo](https://demo.mobiscroll.com/angular/range/book-rental-months-ahead)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-angular/tree/main/src/demos/datepicker/range/book-rental-months-ahead)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/range/book-rental-months-ahead.md), [jQuery](https://demo.mobiscroll.com/jquery/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/angular/range/dots-colors-labels) can be used to display season and pricing information and [half-day styling](https://demo.mobiscroll.com/angular/range/half-day-styling) to show check-in and check-out dates.

Booked dates are [disabled](https://demo.mobiscroll.com/angular/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/angular/datepicker/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/angular/datepicker/api#opt-themeVariant) - option
- [`min`](https://mobiscroll.com/docs/angular/datepicker/api#opt-min) - option
- [`labels`](https://mobiscroll.com/docs/angular/datepicker/api#opt-labels) - option
- [`invalid`](https://mobiscroll.com/docs/angular/datepicker/api#opt-invalid) - option
- [`colors`](https://mobiscroll.com/docs/angular/datepicker/api#opt-colors) - option
- [`controls`](https://mobiscroll.com/docs/angular/datepicker/api#opt-controls) - option
- [`select`](https://mobiscroll.com/docs/angular/datepicker/api#opt-select) - option
- [`display`](https://mobiscroll.com/docs/angular/datepicker/api#opt-display) - option
- [`calendarSize`](https://mobiscroll.com/docs/angular/datepicker/api#opt-calendarSize) - option
- [`calendarType`](https://mobiscroll.com/docs/angular/datepicker/api#opt-calendarType) - option
- [`showRangeLabels`](https://mobiscroll.com/docs/angular/datepicker/api#opt-showRangeLabels) - option
- [`inRangeInvalid`](https://mobiscroll.com/docs/angular/datepicker/api#opt-inRangeInvalid) - option
- [`rangeEndInvalid`](https://mobiscroll.com/docs/angular/datepicker/api#opt-rangeEndInvalid) - option
- [`calendarHeaderTemplate`](https://mobiscroll.com/docs/angular/datepicker/api#template-calendarHeaderTemplate) - template

## Code

### Component

```ts
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { formatDate, MbscModule, setOptions } from '@mobiscroll/angular';

setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

const now = new Date();

@Component({
  selector: 'app-root', 
  templateUrl: './app.component.html',
  standalone: true,
  imports: [CommonModule, MbscModule],
})
export class AppComponent implements OnInit {
  constructor(private http: HttpClient) {}

  min = '2026-10-21T00:00';
  labels: any = [];
  invalid: any = [];
  colors: any = [];
  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,
      },
    },
  ];

  getColors(start: Date, end: Date) {
    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',
      },
    ];
  }

  ngOnInit(): void {
    const y = now.getFullYear();
    const m = now.getMonth();
    this.http.jsonp('https://trial.mobiscroll.com/getrentals/?year=' + y + '&month=' + m, 'callback').subscribe((data: any) => {
      const prices = data.prices;
      const bookings = data.bookings;
      const labels: any = [];
      const invalids: any = [];
      let colors: any = [];
      let endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0);

      for (const price of prices) {
        const booked = bookings.find((b: { checkIn: any }) => 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, ...this.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,
          });
        }
      }
      this.labels = labels;
      this.invalid = invalids;
      this.colors = [...colors, ...this.monthColors];
    });
  }
}
```

### Template

```html
<mbsc-datepicker
  [controls]="['calendar']"
  select="range"
  display="inline"
  [calendarSize]="6"
  calendarType="month"
  [min]="min"
  [labels]="labels"
  [invalid]="invalid"
  [colors]="colors"
  [showRangeLabels]="false"
  [inRangeInvalid]="false"
  [rangeEndInvalid]="true"
  [calendarHeaderTemplate]="headerTemplate"
  class="md-book-rental"
>
  <ng-template #headerTemplate>
    <mbsc-calendar-nav></mbsc-calendar-nav>
    <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></mbsc-calendar-prev>
    <mbsc-calendar-next></mbsc-calendar-next>
  </ng-template>
</mbsc-datepicker>
```

### 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: flex-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-angular.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 angular
   ```

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

   ```
   npm install
   ```

6. Run the project:

   ```
   ng serve
   ```

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

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

## Related demos

- Previous: [Flight Booking](https://demo.mobiscroll.com/angular/range/flight-booking.md) - Build a flight booking date picker with the Angular range component — round-trip and one-way selection.
- Next: [Range Picker for Event Creation](https://demo.mobiscroll.com/angular/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.
