---
title: "Javascript Event calendar Block Past Event Creation Example | Mobiscroll"
component: "Event calendar"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/eventcalendar/disallow-past-event-creation"
---

# Block Past Event Creation - JavaScript Event calendar demo

Keep past dates read-only in a Javascript event calendar — block creation and editing on past days and show toast feedback on failed attempts. Plain JavaScript API.

- [Live demo](https://demo.mobiscroll.com/javascript/eventcalendar/disallow-past-event-creation)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-javascript/tree/main/src/demos/eventcalendar/calendar-view/disallow-past-event-creation)
- This demo in other frameworks: [jQuery](https://demo.mobiscroll.com/jquery/eventcalendar/disallow-past-event-creation.md), [Angular](https://demo.mobiscroll.com/angular/eventcalendar/disallow-past-event-creation.md), [React](https://demo.mobiscroll.com/react/eventcalendar/disallow-past-event-creation.md), [Vue](https://demo.mobiscroll.com/vue/eventcalendar/disallow-past-event-creation.md)

## Description

Sometimes we don't want users to be able to create events in the past or to alter past events. This might be role based in some cases or applied in general to the calendar.

To disable past event creation and manipulation, a couple of things need to be handled:

- **Invalidate dates that are before today** - this takes care of validating event drop and event creation on past dates
- **Mark past events as fixed** - to do this, set the `editable` property of the event object to `false` for the events that should remain fixed

- **Handle past occurrences of recurring events** - recurring events are loaded as a single event and the occurrences are generated by the event calendar. Moving the past occurrences need to be handled in the [`onEventUpdate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventUpdate) and [`onEventCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventCreate) lifecycle events
- **Give feedback to the user** - optionally, a toast can be displayed to give feedback to the user why an event cannot be dropped, moved and created in the past. For this we can use the [`onEventCreateFailed`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventCreateFailed) and [`onEventUpdateFailed`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventUpdateFailed) lifecycle events

## What this demo shows

- A desktop month view event calendar with multiple events displayed directly in the month grid.
- **Calendar header** The header shows the current month and year on the left, and blue month navigation arrows with a `Today` button (for jumping back to the current date) between them on the right. 
- **Past dates** Day cells before today are disabled and rendered with a gray background.
- **Disabled past days** Disabled past dates block event creation and drag and drop interactions on those cells.
- **Past events** Events on past dates remain visible, but they cannot be moved or repositioned.
- **Failed past updates** If a user tries to move a past recurring event, a toast appears at the bottom center with the message `Can't move past events.`
- **Overflow handling** The number of visible event labels depends on the available height in each day cell. Additional events are collapsed behind an `X more` link.
- **Popover** Clicking the `X more` link opens a popover that shows the hidden events for that day.
- **Label interaction** Hovering over or clicking an event label selects it and highlights the selected label.
- **Event creation** Users can create events on future dates by clicking and dragging across calendar cells or by double-clicking a day cell.
- **Hover on past days** Hovering a disabled past day shows a disabled icon.
- **Day cell states for future days** Hovering a day cell highlights the day number with a gray background, while clicking the empty part of the cell selects the day and highlights the day number with a blue background.
- **Future dates** Future day cells remain interactive and support new event creation.

## Best for

- **Booking and scheduling flows** Preventing users from creating or changing events in the past when only current and future availability should be managed.
- **Operational calendars** Keeping historical calendar data fixed for teams that use the month view for planning upcoming work, appointments, or activities.
- **Mixed-interaction month views** Allowing users to keep creating and editing future events while clearly separating past dates as read-only.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-themeVariant) - option
- [`view`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-view) - option
- [`labels`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-labels) - option
- [`invalid`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-invalid) - option
- [`clickToCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToResize) - option
- [`onEventCreateFailed`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventCreateFailed) - event
- [`onEventUpdateFailed`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventUpdateFailed) - event
- [`onEventCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventCreate) - event
- [`updateEvent`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-updateEvent) - method
- [`onEventUpdate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventUpdate) - event
- [`setEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-setEvents) - method

## Code

### JS

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

var today = new Date();

var inst = mobiscroll.eventcalendar('#demo-disallow-past-event-creation', {
  view: {
    calendar: {
      labels: true,
    },
  },
  invalid: [
    {
      recurring: {
        repeat: 'daily',
        until: today,
      },
    },
  ],
  clickToCreate: true,
  dragToCreate: true,
  dragToMove: true,
  dragToResize: true,
  onEventCreateFailed: function (args) {
    if (!args.originEvent) {
      mobiscroll.toast({
        message: "Can't create event in the past",
      });
    }
  },
  onEventUpdateFailed: function (args) {
    if (!args.oldEventOccurrence) {
      mobiscroll.toast({
        message: "Can't move event in the past",
      });
    }
  },
  onEventCreate: function (args) {
    var oldEvent = args.originEvent;
    var start = oldEvent && oldEvent.start ? oldEvent.start : null;

    // Handle recurring events
    if (start && start < today) {
      inst.updateEvent(oldEvent);
      mobiscroll.toast({
        message: "Can't move past event",
      });
      return false;
    }
  },
  onEventUpdate: function (args) {
    var oldEvent = args.oldEvent;
    var start = oldEvent && oldEvent.start ? oldEvent.start : null;
    var oldEventOccurrence = args.oldEventOccurrence;
    var occurrenceStart = oldEventOccurrence && oldEventOccurrence.start ? oldEventOccurrence.start : null;

    // Handle recurring events
    if ((start && start < today) || (occurrenceStart && occurrenceStart < today)) {
      inst.updateEvent(oldEvent);
      return false;
    }
  },
});

mobiscroll.getJson(
  'https://trial.mobiscroll.com/events/?vers=5',
  function (events) {
    for (var i = 0; i < events.length; ++i) {
      var event = events[i];
      // Convert dates to date objects
      event.start = event.start ? new Date(event.start) : event.start;
      event.end = event.end ? new Date(event.end) : event.end;
      // Mark past events as fixed by setting the event.editable property to false
      event.editable = event.start && today < event.start;
    }
    inst.setEvents(events);
  },
  'jsonp',
);
```

### HTML

```html
<div id="demo-disallow-past-event-creation" class="md-disallow-past-event-creation"></div>
```

### CSS

```css
.md-disallow-past-event-creation .mbsc-readonly-event {
    opacity: .6;
}
```

## Implementation notes

- Use `view: { calendar: { labels: true } }`. Enable all four interaction modes: `clickToCreate: true`, `dragToCreate: true`, `dragToMove: true`, `dragToResize: true`.
- Compute `today = new Date()` at module level. Pass `invalid: [{ recurring: { repeat: 'daily', until: today } }]` - this single entry blocks all dates up to and including today, preventing event creation and drop on past day cells.
- Load events via `getJson`. After loading, convert `event.start` and `event.end` to `Date` objects, then set `event.editable = event.start && today < event.start` - only future events are editable; past events get `editable: false`, which locks them against drag/resize/delete. JS/jQuery: call `inst.setEvents(events)`.
- **`onEventCreateFailed`** - show a toast (`"Can't create event in the past"`) only when `args.originEvent` is absent (guards against false positives from recurring events).
- **`onEventUpdateFailed`** - show a toast (`"Can't move event in the past"`) only when `args.oldEventOccurrence` is absent.
- **`onEventCreate`** - handles the recurring event edge case: if `args.originEvent?.start < today`, show a toast (`"Can't move past event"`) and `return false`. JS/jQuery: also call `inst.updateEvent(args.originEvent)` before returning false to restore the event.
- **`onEventUpdate`** - if `args.oldEvent.start < today` or `args.oldEventOccurrence?.start < today`, `return false`. JS/jQuery: also call `inst.updateEvent(args.oldEvent)` before returning false.

## 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: [Recurring Events Editor](https://demo.mobiscroll.com/javascript/eventcalendar/recurring-event-add-edit-dialog.md) - Add recurring event management to a Javascript event calendar — use preset daily, weekly, monthly, and yearly rules or a custom recurrence editor.
- Next: [Bulk Actions](https://demo.mobiscroll.com/javascript/eventcalendar/event-bulk-actions-edit-delete-update.md) - Multi-select events by keyboard in a Javascript calendar - bulk delete, update, or run custom actions via action panel or right-click context menu.
