---
title: "Javascript Calendar Disable & Validate Dates Example | Mobiscroll"
component: "Calendar"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/calendar/disabled-invalid-values"
---

# Disable & Validate Dates - JavaScript Calendar demo

Restrict selectable dates in a Javascript calendar date picker using recurring dates and min/max limits — for appointment booking and leave forms. Plain JS api for usage everywhere.

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

## Description

Enforcing validation is essential to a great UX. First make sure to have the [min & max values right](https://demo.mobiscroll.com/javascript/calendar/min-max-restrictions) and then work your way through disabled values.

Depending on your situation, you have two options:

- **Set invalid** - set the invalids through the [`invalid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-invalid) option.
- **Set valid** - set the valids through the [`valid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-valid) option.

Both the [`invalid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-invalid) and [`valid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-valid) options support the following:

- **Exact dates** - Passing exact values like: `'2020-05-20'` will disable/enable the specific day
- **Date ranges** - Passing `start` and `end` value pairs will disable/enable specific days and/or times that fall into that range
- **Recurring dates** - Passing recurrence rules as objects or in RRULE string format will be parsed. For [more information on recurrence check out the rule generator](https://demo.mobiscroll.com/javascript/calendar/recurring-values)

Exact dates and the start/end pairs can be passed as [JS date objects, ISO date strings or Moment.js objects](https://demo.mobiscroll.com/javascript/calendar/date-object-ISO-8601-moment). Having invalids set up correctly not just enhances the UX, but improves performance.

The passed date-times can also contain timezone data which requires a [`timezonePlugin`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-timezonePlugin) to be interpreted correctly.

**Using date-times across different timezones?** [Learn more about timezone support →](https://demo.mobiscroll.com/javascript/calendar/setting-the-picker-timezone)

## What this demo shows

- A segmented control switches between a date picker, selected by default, a time picker, and a date and time picker. Each mode demonstrates how to disable values relevant to that picker.
- **Header navigation** The month and year label in the upper-left corner opens month and year selection controls. The previous and next arrow buttons on the right move between months.
- **Month view** A fixed weekday header displays abbreviated day names from Sunday through Saturday, with dates arranged in a grid below.
- **Month navigation** Users can also change the displayed month by dragging the calendar left or right.
- **Day cell states** Hovering over a day gives its number a gray background. Selecting a day gives its number a blue background. The current date is highlighted by default and remains blue when another date is selected.
- **Disabled values** Disabled dates cannot be selected in the date picker or the date and time picker. Disabled times cannot be selected in the time pickers.
- **Adjacent months** Dates from the previous and next months use a muted style. Selecting one navigates to the corresponding month.
- **Date and time picker** In date and time mode, a scroller-based time picker appears beside the single-month calendar. Separate wheels provide hours from 1 to 12, minutes from 0 to 59, and AM/PM selection.
- **Time picker** In time picker mode, separate scroller wheels provide hours from 1 to 12, minutes from 0 to 59, and AM/PM selection.
- **Control panel** Below the picker-mode segmented control, users can switch between defining invalid values, selected by default, and setting valid rules. They can configure exact dates, recurring dates such as weekends or holidays, and one or more date ranges.

## Best for

- **Appointment booking** Prevent customers from selecting dates when a business is closed, fully booked, or unavailable.
- **Employee leave requests** Block weekends, company holidays, and dates outside an allowed request period.
- **Travel and accommodation booking** Disable sold-out dates, unavailable arrival dates, or maintenance periods.
- **Delivery scheduling** Exclude non-delivery days, public holidays, and dates when capacity is unavailable.
- **Course and event registration** Restrict selection to scheduled session dates and disable dates after registration closes.

## Tutorial

- (x) Date
- ( ) Time
- ( ) Date & time

### Do you want to

- (x) Set invalid values
- ( ) Set valid values

### Disable exact dates

- [x] Disable these days

`2026-10-22, 2026-10-25`

### Disable recurring dates

- [x] Disable weekends
- [ ] Disable holidays (Christmas Eve, New Years)
- [ ] Disable the first and last of every month

### Disable one or more date ranges

- [x] Disable this range

`2026-10-27 - 2026-11-03`

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar'],
    invalid: [
		'2026-10-22',
		'2026-10-25',
		{
			start: '2026-10-27',
			end: '2026-11-03'
		},
		{
			recurring: {
				repeat: 'weekly',
				weekDays: 'SA,SU'
			}
		}
	]
});
```

With "Time":

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['time'],
    invalid: [
		{
			start: '11:30',
			end: '11:30',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '14:30',
			end: '14:30',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '18:00',
			end: '18:00',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '22:00',
			end: '22:00',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '02:00',
			end: '04:30',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '13:00',
			end: '14:00',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '15:00',
			end: '15:30',
			recurring: {
				repeat: 'daily'
			}
		},
		{
			start: '21:30',
			end: '22:30',
			recurring: {
				repeat: 'daily'
			}
		}
	]
});
```

With "Date & time":

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar', 'time'],
    invalid: [
		{
			start: '2022-04-28T09:00',
			end: '2022-04-28T09:00'
		},
		{
			start: '2022-04-30T11:30',
			end: '2022-04-30T11:30'
		},
		{
			start: '2022-04-01T09:00',
			end: '2022-04-01T18:30'
		},
		{
			start: '2022-04-02T15:00',
			end: '2022-04-02T19:00'
		}
	]
});
```

With "Set valid values":

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar']
    valid: [
		'2026-10-22',
		'2026-10-25',
		{
			start: '2026-10-27',
			end: '2026-11-03'
		},
		{
			recurring: {
				repeat: 'weekly',
				weekDays: 'MO, TU, WE, TH, FR'
			}
		}
	]
});
```

With "Disable these days" off:

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar'],
    invalid: [
		{
			start: '2026-10-27',
			end: '2026-11-03'
		},
		{
			recurring: {
				repeat: 'weekly',
				weekDays: 'SA,SU'
			}
		}
	]
});
```

With "Disable weekends" off:

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar'],
    invalid: [
		'2026-10-22',
		'2026-10-25',
		{
			start: '2026-10-27',
			end: '2026-11-03'
		}
	]
});
```

With "Disable holidays (Christmas Eve, New Years)" on:

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar'],
    invalid: [
		'2026-10-22',
		'2026-10-25',
		{
			recurring: {
				repeat: 'yearly',
				day: 24,
				month: 12
			}
		},
		{
			recurring: {
				repeat: 'yearly',
				day: 31,
				month: 12
			}
		},
		{
			start: '2026-10-27',
			end: '2026-11-03'
		},
		{
			recurring: {
				repeat: 'weekly',
				weekDays: 'SA,SU'
			}
		}
	]
});
```

With "Disable the first and last of every month" on:

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar'],
    invalid: [
		'2026-10-22',
		'2026-10-25',
		{
			recurring: {
				repeat: 'monthly',
				day: 1
			}
		},
		{
			recurring: {
				repeat: 'monthly',
				day: -1
			}
		},
		{
			start: '2026-10-27',
			end: '2026-11-03'
		},
		{
			recurring: {
				repeat: 'weekly',
				weekDays: 'SA,SU'
			}
		}
	]
});
```

With "Disable this range" off:

```js
mobiscroll.datepicker('#mycalendar', {
    controls: ['calendar'],
    invalid: [
		'2026-10-22',
		'2026-10-25',
		{
			recurring: {
				repeat: 'weekly',
				weekDays: 'SA,SU'
			}
		}
	]
});
```

## 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
- [`display`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-display) - option
- [`invalid`](https://mobiscroll.com/docs/javascript/datepicker/api#opt-invalid) - option

## Code

### JS

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

mobiscroll.datepicker('#demo', {
  controls: ['calendar'],
  display: 'inline',
  invalid: [
    '2020-02-12',
    '2020-05-20',
    {
      recurring: {
        repeat: 'weekly',
        weekDays: 'SA,SU',
      },
    },
    {
      recurring: {
        repeat: 'yearly',
        day: 24,
        month: 12,
      },
    },
    {
      recurring: {
        repeat: 'yearly',
        day: 31,
        month: 12,
      },
    },
    {
      recurring: {
        repeat: 'monthly',
        day: 1,
      },
    },
    {
      recurring: {
        repeat: 'monthly',
        day: -1,
      },
    },
    {
      start: '2020-03-15',
      end: '2020-03-30',
    },
    {
      start: '2020-07-05',
      end: '2020-08-20',
    },
  ],
});
```

### HTML

```html
<div id="demo"></div>
```

## Implementation notes

- `controls` can be set to `['calendar']` (Date), `['time']` (Time), or `['calendar', 'time']` (Date & time) to switch the single `Datepicker` instance between three modes.
- Only one of `invalid` (disables the listed dates/times, everything else stays selectable) or `valid` (only the listed dates/times are selectable) is set at a time - the other is passed as `undefined` via `setOptions`.
- Specific days can be added to `invalid`/`valid` as an array of `'YYYY-MM-DD'` date strings.
- Recurring rules can be added to `invalid`/`valid`, e.g. weekends (`{ recurring: { repeat: 'weekly', weekDays: 'SA,SU' } }`), weekdays (`{ recurring: { repeat: 'weekly', weekDays: 'MO,TU,WE,TH,FR' } }`), holidays as yearly rules (`{ recurring: { repeat: 'yearly', day: 24, month: 12 } }`, `{ recurring: { repeat: 'yearly', day: 31, month: 12 } }`), and first/last of month (`{ recurring: { repeat: 'monthly', day: 1 } }`, `{ recurring: { repeat: 'monthly', day: -1 } }` - a negative `day` counts back from the end of the month).
- A `{ start, end }` range (formatted as `'YYYY-MM-DD'` strings, via `select: 'range'`) can also be added to `invalid`/`valid`.
- Exact times can be added to `invalid`/`valid` as `{ start: time, end: time, recurring: { repeat: 'daily' } }` entries.
- Time ranges can be added to `invalid`/`valid` as `{ start, end, recurring: { repeat: 'daily' } }` entries.
- In date & time mode, full ISO 8601 datetime strings and `start - end` datetime pairs produce `{ start, end }` objects with no `recurring` (or `{ start: time, end: time, recurring: { repeat: 'daily' } }` when only a time-of-day is given).
- Changes are applied by calling `.setOptions({ invalid: [...] })` or `.setOptions({ valid: [...] })` on the calendar instance.
- Dates/times covered by `invalid` render disabled and cannot be selected; when `valid` is set, only the listed dates/times remain selectable.

## 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: [Min & Max Date Restrictions](https://demo.mobiscroll.com/javascript/calendar/min-max-restrictions.md) - Restrict selectable dates and times in a Javascript date picker with min and max values — for appointment booking, travel, or registration forms.
- Next: [Recurring Date Rules](https://demo.mobiscroll.com/javascript/calendar/recurring-values.md) - Configure recurring date rules in a Javascript calendar — invalid, mark, color, or label dates repeating daily, weekly, monthly, or yearly, with exceptions.
