---
title: "JQuery Timeline CRUD Events Example | Mobiscroll"
component: "Timeline"
framework: "jQuery"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/jquery/timeline/create-read-update-delete-CRUD"
---

# CRUD Events - jQuery Timeline demo

Add, edit, move, resize, and delete events on a JQuery Timeline — drag or double-click to create; set color, dates and all-day options in a dialog. For jQuery or jQuery Mobile.

- [Live demo](https://demo.mobiscroll.com/jquery/timeline/create-read-update-delete-CRUD)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-jquery/tree/main/src/demos/eventcalendar/timeline/create-read-update-delete-CRUD)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/create-read-update-delete-CRUD.md), [Angular](https://demo.mobiscroll.com/angular/timeline/create-read-update-delete-CRUD.md), [React](https://demo.mobiscroll.com/react/timeline/create-read-update-delete-CRUD.md), [Vue](https://demo.mobiscroll.com/vue/timeline/create-read-update-delete-CRUD.md)

## Description

### Create new events

Drag to create and click to create is enabled. Events can be created by dragging or with double clicks. As soon as the initial position is confirmed, a temporary event is created and a custom edit dialog is shown for refinement. On cancel the temporary event will be removed and on confirmation the event will stay in the calendar.

### Edit existing events

Drag to resize and drag to move is enabled. Events can be reordered and resized. In addition to that, clicking on the event will open a custom dialog that enables editing the various properties.

### Delete events

Delete can be implemented inside the edit dialog with a button. It's just a matter of removing it from the data object. If a dialog is not shown on click, focused events can be deleted with the *backspace* and *delete* keys.

**Interested in adding recurrence configuration?** [Check out this example →](https://demo.mobiscroll.com/jquery/eventcalendar/recurring-event-add-edit-dialog)

## What this demo shows

- A desktop daily timeline where hours are arranged horizontally and a hierarchical resource tree arranged vertically on the left.
- **Header navigation** The month and year label opens date navigation, while the previous and next arrows move between days and the Today button returns to the current date.
- **Day view** The strip below the header shows the selected days, with the current date highlighted. The timeline displays hourly columns from 12 AM to 12 PM.
- **Resources** Multiple resources are shown as separate timeline rows.
- **Current time** A vertical blue line with a time label marks the current time.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event cards** Events appear as colored cards with a colored stripe on the left, the event title in bold, and the exact start and end time displayed below the title.
- **Date positioning** Events are positioned by their assigned resource and exact date and time range.
- **Event interaction** Events highlight on hover and show drag and resize handles for repositioning or changing duration.
- **Event creation** Double-clicking the time grid or clicking and dragging on it creates a new event.
- **New event dialog** Creating an event opens a dialog with fields for title, description, all-day, start and end date selection, travel time, event color, and busy or free status.
- **Date selection** The start and end inputs open a date picker calendar with range selection.
- **Cancel behavior** Clicking outside the dialog or pressing Cancel closes it and removes the temporary event from the timeline.
- **Event editing** Clicking or tapping an existing event opens the same dialog in edit mode with the current values prefilled.
- **Editable properties** In edit mode, the event details and event color can be changed before saving.
- **Save and close behavior** Clicking outside the dialog or pressing Cancel closes the editor without applying changes, while Save updates the event.
- **Delete flow** The edit dialog includes a Delete event action that removes the event from the timeline.
- **Undo feedback** After deletion, a centered bottom toast appears with an Undo action so the deleted event can be restored.
- **Responsive behavior** The dialog adapts to screen size and device type, using touch-optimized controls such as scrollers on smaller or touch devices.
- **Mobile presentation** On smaller screens, the dialog is shown as a sheet instead of a popover.
- **Scrolling** The timeline supports horizontal and vertical scrolling for navigating through time and resources.

## Best for

- **Daily event management** Managing create, read, update, and delete workflows in a daily-based timeline view.
- **General scheduling** Applications where users need to add, edit, and remove events directly from the timeline.
- **Mixed event types** Timelines that need to handle single-day, multi-day, all-day, and timed events in the same interface.
- **Responsive scheduling UIs** Products that need the same event management flow to work well on desktop and touch devices.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-themeVariant) - option
- [`setOptions`](https://mobiscroll.com/docs/jquery/datepicker/api#method-setOptions) - method
- [`controls`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-controls) - option
- [`responsive`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-responsive) - option
- [`touchUi`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-touchUi) - option
- [`setOptions`](https://mobiscroll.com/docs/jquery/popup/api#method-setOptions) - method
- [`anchor`](https://mobiscroll.com/docs/jquery/popup/api#opt-anchor) - option
- [`headerText`](https://mobiscroll.com/docs/jquery/popup/api#opt-headerText) - option
- [`buttons`](https://mobiscroll.com/docs/jquery/popup/api#opt-buttons) - option
- [`updateEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-updateEvent) - method
- [`navigateToEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-navigateToEvent) - method
- [`close`](https://mobiscroll.com/docs/jquery/popup/api#method-close) - method
- [`cssClass`](https://mobiscroll.com/docs/jquery/popup/api#opt-cssClass) - option
- [`onClose`](https://mobiscroll.com/docs/jquery/popup/api#event-onClose) - event
- [`removeEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-removeEvent) - method
- [`open`](https://mobiscroll.com/docs/jquery/popup/api#method-open) - method
- [`clickToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToResize) - option
- [`view`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-view) - option
- [`data`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-resources) - option
- [`onEventClick`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventClick) - event
- [`onEventCreated`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreated) - event
- [`onEventDeleted`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventDeleted) - event
- [`addEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-addEvent) - method
- [`select`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-select) - option
- [`startInput`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-startInput) - option
- [`endInput`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-endInput) - option
- [`showRangeLabels`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-showRangeLabels) - option
- [`onChange`](https://mobiscroll.com/docs/jquery/datepicker/api#event-onChange) - event
- [`display`](https://mobiscroll.com/docs/jquery/popup/api#opt-display) - option
- [`showArrow`](https://mobiscroll.com/docs/jquery/popup/api#opt-showArrow) - option
- [`showOverlay`](https://mobiscroll.com/docs/jquery/popup/api#opt-showOverlay) - option
- [`responsive`](https://mobiscroll.com/docs/jquery/popup/api#opt-responsive) - option
- [`fullScreen`](https://mobiscroll.com/docs/jquery/popup/api#opt-fullScreen) - option
- [`scrollLock`](https://mobiscroll.com/docs/jquery/popup/api#opt-scrollLock) - option
- [`width`](https://mobiscroll.com/docs/jquery/popup/api#opt-width) - option
- [`touchUi`](https://mobiscroll.com/docs/jquery/popup/api#opt-touchUi) - option

## Code

### JS

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

$(function () {
  function toggleDatetimePicker(allDay) {
    // Toggle between date and datetime picker
    eventStartEndPicker.setOptions({
      controls: allDay ? ['date'] : ['datetime'],
      responsive: allDay
        ? { medium: { controls: ['calendar'], touchUi: false } }
        : { medium: { controls: ['calendar', 'time'], touchUi: false } },
    });
  }

  function toggleTravelTime(allDay) {
    if (allDay) {
      $timeGroup.remove();
    } else {
      $timeGroupParent.append($timeGroup);
    }
  }

  // Fills the popup with the event's data
  function fillPopup(event, resourceColor) {
    // Load event properties
    eventId = event.id;
    eventTitle = event.title || '';
    eventDescription = event.description || '';
    eventAllDay = event.allDay;
    eventStart = event.start;
    eventEnd = event.end;
    eventBuffer = event.bufferBefore || 0;
    eventColor = event.color || resourceColor;
    eventStatus = event.free;
    eventResource = event.resource;

    // Set event fields
    $eventTitle.mobiscroll('getInst').value = eventTitle;
    $eventDescription.mobiscroll('getInst').value = eventDescription;
    $eventAllDay.mobiscroll('getInst').checked = eventAllDay;
    eventStartEndPicker.setVal([eventStart, eventEnd]);
    $eventBuffer.val(eventBuffer);
    highlightColor(eventColor);
    updateColorPreview(eventColor);
    if (eventStatus) {
      $eventStatusFree.mobiscroll('getInst').checked = true;
    } else {
      $eventStatusBusy.mobiscroll('getInst').checked = true;
    }
    toggleDatetimePicker(eventAllDay);
    toggleTravelTime(eventAllDay);
  }

  function getEventData() {
    return {
      id: eventId,
      title: eventTitle,
      description: eventDescription,
      allDay: eventAllDay,
      start: eventStart,
      end: eventEnd,
      bufferBefore: eventBuffer,
      color: eventColor,
      free: eventStatus,
      resource: eventResource,
    };
  }

  function createAddPopup(event, target, color) {
    var success = false;

    // Hide delete button inside add popup
    $eventDeleteButton.parent().hide();

    // Set popup header text and buttons for adding
    addEditPopup.setOptions({
      anchor: target,
      headerText: 'New event',
      buttons: [
        'cancel',
        {
          text: 'Add',
          keyCode: 'enter',
          handler: function () {
            var newEvent = getEventData();
            calendar.updateEvent(newEvent);
            calendar.navigateToEvent(newEvent);
            success = true;
            addEditPopup.close();
          },
          cssClass: 'mbsc-popup-button-primary',
        },
      ],
      onClose: function () {
        // Remove event if popup is cancelled
        if (!success) {
          calendar.removeEvent(event);
        }
      },
    });

    fillPopup(event, color);
    addEditPopup.open();
  }

  function createEditPopup(event, target, color) {
    // Show delete button inside edit popup
    $eventDeleteButton.parent().show();

    editedEvent = event;

    // Set popup header text and buttons
    addEditPopup.setOptions({
      headerText: 'Edit event',
      anchor: target,
      buttons: [
        'cancel',
        {
          text: 'Save',
          keyCode: 'enter',
          handler: function () {
            var updatedEvent = getEventData();
            calendar.updateEvent(updatedEvent);
            calendar.navigateToEvent(updatedEvent);
            addEditPopup.close();
          },
          cssClass: 'mbsc-popup-button-primary',
        },
      ],
    });

    fillPopup(event, color);
    addEditPopup.open();
  }

  function highlightColor(color) {
    $('.mds-crud-color-value').removeClass('mds-crud-color-value-selected');
    $('.mds-crud-color-value[data-value="' + color + '"]').addClass('mds-crud-color-value-selected');
  }

  function updateColorPreview(color) {
    $colorPreview.css('background', color || '');
  }

  function applySelectedColor(color) {
    eventColor = color;
    updateColorPreview(color);
    eventColorPicker.close();
  }

  var editedEvent;
  var selectedColor;

  var eventId;
  var eventTitle;
  var eventDescription;
  var eventAllDay;
  var eventStart;
  var eventEnd;
  var eventBuffer;
  var eventColor;
  var eventStatus;
  var eventResource;

  var $eventTitle = $('#crud-popup-event-title');
  var $eventDescription = $('#crud-popup-event-desc');
  var $eventAllDay = $('#crud-popup-event-all-day');
  var $eventBuffer = $('#crud-popup-event-buffer');
  var $eventColor = $('#crud-popup-event-color');
  var $colorPreview = $('#crud-popup-event-color-preview');
  var $eventStatusBusy = $('#crud-popup-event-status-busy');
  var $eventStatusFree = $('#crud-popup-event-status-free');
  var $eventDeleteButton = $('#crud-popup-event-delete');
  var $timeGroup = $('#crud-popup-time-group');
  var $timeGroupParent = $timeGroup.parent();

  var myEvents = [
    {
      id: 1,
      start: '2026-10-22T13:00',
      end: '2026-10-22T15:00',
      title: "Lunch @ Butcher's",
      description: '',
      allDay: false,
      bufferBefore: 15,
      free: true,
      resource: 3,
    },
    {
      id: 2,
      start: '2026-10-22T14:00',
      end: '2026-10-22T16:00',
      title: 'Conference',
      description: '',
      allDay: false,
      bufferBefore: 30,
      free: false,
      resource: 5,
    },
    {
      id: 3,
      start: '2026-10-22T18:00',
      end: '2026-10-22T22:00',
      title: 'Site Visit',
      description: '',
      allDay: false,
      bufferBefore: 60,
      free: true,
      resource: 4,
    },
    {
      id: 4,
      start: '2026-10-22T10:30',
      end: '2026-10-22T13:00',
      title: 'Stakeholder mtg.',
      description: '',
      allDay: false,
      free: false,
      resource: 1,
    },
  ];

  var myResources = [
    {
      id: 1,
      name: 'Resource A',
      color: '#ffeb3c',
    },
    {
      id: 2,
      name: 'Resource B',
      color: '#f44437',
    },
    {
      id: 3,
      name: 'Resource C',
      color: '#3f51b5',
    },
    {
      id: 4,
      name: 'Resource D',
      color: '#4baf4f',
    },
    {
      id: 5,
      name: 'Resource E',
      color: '#ff9900',
    },
  ];

  // Init the event calendar
  var calendar = $('#demo-crud-event-calendar')
    .mobiscroll()
    .eventcalendar({
      clickToCreate: 'double',
      dragToCreate: true,
      dragToMove: true,
      dragToResize: true,
      view: {
        timeline: { type: 'day' },
      },
      data: myEvents,
      resources: myResources,
      onEventClick: function (args) {
        createEditPopup(args.event, args.domEvent.currentTarget, args.resourceObj.color);
      },
      onEventCreated: function (args) {
        createAddPopup(args.event, args.target, args.resourceObj.color);
      },
      onEventDeleted: function (args) {
        mobiscroll.snackbar({
          button: {
            action: function () {
              calendar.addEvent(args.event);
            },
            text: 'Undo',
          },
          message: 'Event deleted',
        });
      },
    })
    .mobiscroll('getInst');

  // Init event start/end date picker
  var eventStartEndPicker = $('#crud-popup-event-dates')
    .mobiscroll()
    .datepicker({
      controls: ['date'],
      select: 'range',
      startInput: '#crud-popup-event-start',
      endInput: '#crud-popup-event-end',
      showRangeLabels: false,
      touchUi: true,
      responsive: { medium: { touchUi: false } },
      onChange: function (args) {
        var dates = args.value;
        eventStart = dates[0];
        eventEnd = dates[1];
      },
    })
    .mobiscroll('getInst');

  // Init event color picker
  var eventColorPicker = $('#crud-color-picker-popup')
    .mobiscroll()
    .popup({
      display: 'bottom',
      contentPadding: false,
      showArrow: false,
      showOverlay: false,
      buttons: [
        'cancel',
        {
          text: 'Set',
          keyCode: 'enter',
          handler: function () {
            applySelectedColor(selectedColor);
          },
          cssClass: 'mbsc-popup-button-primary',
        },
      ],
      responsive: {
        medium: {
          display: 'anchored',
          anchor: $eventColor[0],
          buttons: [],
        },
      },
    })
    .mobiscroll('getInst');

  var addEditPopup = $('#crud-add-edit-popup')
    .mobiscroll()
    .popup({
      display: 'bottom',
      contentPadding: false,
      fullScreen: true,
      scrollLock: false,
      responsive: {
        medium: {
          display: 'anchored',
          width: 400,
          fullScreen: false,
          touchUi: false,
        },
      },
    })
    .mobiscroll('getInst');

  // Attach event handlers

  $eventTitle.on('input', function () {
    eventTitle = this.value;
  });

  $eventDescription.on('change', function () {
    eventDescription = this.value;
  });

  $eventAllDay.on('change', function () {
    eventAllDay = this.checked;
    toggleDatetimePicker(eventAllDay);
    toggleTravelTime(eventAllDay);
  });

  $eventBuffer.on('change', function () {
    eventBuffer = +this.value;
  });

  $('.mds-crud-popup-event-status').on('change', function () {
    eventStatus = this.value === 'free';
  });

  $eventDeleteButton.on('click', function () {
    calendar.removeEvent(editedEvent);
    addEditPopup.close();

    mobiscroll.snackbar({
      button: {
        action: function () {
          calendar.addEvent(editedEvent);
        },
        text: 'Undo',
      },
      message: 'Event deleted',
    });
  });

  $eventColor.on('click', function () {
    eventColorPicker.open();
  });

  $('.mds-crud-color-value').on('click', function (ev) {
    var color = $(ev.currentTarget).data('value');
    selectedColor = color;
    highlightColor(color);

    if (!eventColorPicker.s.buttons.length) {
      applySelectedColor(color);
    }
  });
});
```

### HTML

```html
<div id="demo-crud-event-calendar"></div>

<div style="display: none">
  <div id="crud-add-edit-popup">
    <div class="mbsc-form-group">
      <label>
        Title
        <input mbsc-input id="crud-popup-event-title" />
      </label>
      <label>
        Description
        <textarea mbsc-textarea id="crud-popup-event-desc"></textarea>
      </label>
    </div>
    <div class="mbsc-form-group">
      <div>
        <label>
          All-day
          <input mbsc-switch id="crud-popup-event-all-day" type="checkbox" />
        </label>
        <div id="crud-popup-event-dates"></div>
        <label>
          Starts
          <input mbsc-input id="crud-popup-event-start" />
        </label>
        <label>
          Ends
          <input mbsc-input id="crud-popup-event-end" />
        </label>
        <label id="crud-popup-time-group">
          <select data-label="Travel time" mbsc-dropdown id="crud-popup-event-buffer">
            <option value="0">None</option>
            <option value="5">5 minutes</option>
            <option value="15">15 minutes</option>
            <option value="30">30 minutes</option>
            <option value="60">1 hour</option>
            <option value="90">1.5 hours</option>
            <option value="120">2 hours</option>
          </select>
        </label>
      </div>
      <div id="crud-event-color-picker" class="mbsc-flex mds-crud-event-color-cont">
        <div class="mbsc-flex-1-0">Color</div>
        <div id="crud-popup-event-color">
          <div id="crud-popup-event-color-preview" class="mds-crud-selected-event-color"></div>
        </div>
      </div>
      <label>
        Show as busy
        <input id="crud-popup-event-status-busy" class="mds-crud-popup-event-status" mbsc-segmented type="radio" name="event-status" value="busy" />
      </label>
      <label>
        Show as free
        <input id="crud-popup-event-status-free" class="mds-crud-popup-event-status" mbsc-segmented type="radio" name="event-status" value="free" />
      </label>
      <div class="mbsc-button-group">
        <button class="mbsc-button-block" id="crud-popup-event-delete" mbsc-button data-color="danger" data-variant="outline">
          Delete event
        </button>
      </div>
    </div>
  </div>

  <div id="crud-color-picker-popup">
    <div class="mbsc-flex mds-crud-color-row">
      <div class="mds-crud-color-value" data-value="#ffeb3c">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #ffeb3c"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#ff9900">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #ff9900"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#f44437">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #f44437"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#ea1e63">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #ea1e63"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#9c26b0">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #9c26b0"></div>
      </div>
    </div>
    <div class="mbsc-flex mds-crud-color-row">
      <div class="mds-crud-color-value" data-value="#3f51b5">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #3f51b5"></div>
      </div>
      <div class="mds-crud-color-value" data-value="">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#009788">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #009788"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#4baf4f">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #4baf4f"></div>
      </div>
      <div class="mds-crud-color-value" data-value="#7e5d4e">
        <div class="mds-crud-color mbsc-icon mbsc-font-icon mbsc-icon-material-check" style="background: #7e5d4e"></div>
      </div>
    </div>
  </div>
</div>
```

### CSS

```css
.mds-crud-event-color-cont {
  margin: 16px;
  align-items: center;
  cursor: pointer;
}

.mds-crud-selected-event-color {
  width: 30px;
  height: 30px;
  border-radius: 15px;
  margin-right: 10px;
  margin-left: 240px;
  background: #5ac8fa;
}

.mds-crud-color-row {
  justify-content: center;
  margin: 5px;
}

.mds-crud-color {
  position: relative;
  min-width: 46px;
  min-height: 46px;
  margin: 2px;
  cursor: pointer;
  border-radius: 23px;
  background: #5ac8fa;
}

.mds-crud-color:before {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -10px;
  margin-left: -10px;
  color: #f7f7f7;
  font-size: 20px;
  text-shadow: 0 0 3px #000;
  display: none;
}

.mds-crud-color-value {
  padding: 3px;
  margin: 2px;
}

.mds-crud-color-value.mds-crud-color-value-selected,
.mds-crud-color-value:hover {
  box-shadow: inset 0 0 0 3px #007bff;
  border-radius: 48px;
}

.mds-crud-color-value.mds-crud-color-value-selected .mds-crud-color:before {
  display: block;
}
```

## Implementation notes

- Use `timeline: { type: 'day' }` - a single-day timeline with each resource as a row.
- Enable all four interaction modes: `clickToCreate: true`, `dragToCreate: true`, `dragToMove: true`, `dragToResize: true`.
- Define 5 resources (A-E) with `id`, `name`, and `color`.
- Start with 4 sample events using `dyndatetime` offsets for today. Each event carries: `id`, `title`, `description`, `allDay`, `start`, `end`, `bufferBefore`, `free`, and `resource`.
- Handle three calendar events: `onEventClick` → opens the edit popup (passes `args.event`, `args.domEvent.currentTarget` as anchor, `args.resourceObj.color` as fallback color); `onEventCreated` → opens the add popup (passes `args.event`, `args.target`, `args.resourceObj.color`; the event is already temporarily placed on the calendar by Mobiscroll); `onEventDeleted` → shows a snackbar ("Event deleted") with an "Undo" button that adds the event back.
- Maintain an `isEdit` flag and an `editedEvent` reference. A `fillPopup(event, resourceColor)` helper populates all form fields from the event object, falling back to `resourceColor` for color when the event has none.
- **Edit mode** (`createEditPopup`): set `isEdit = true`, store `editedEvent`, set popup anchor to the clicked element, call `fillPopup`, open with "Edit event" header and a "Save" button.
- **Add mode** (`createAddPopup`): set `isEdit = false`, set `isSuccess = false`, set popup anchor to `args.target`, call `fillPopup`, open with "New Event" header and an "Add" button.
- **On popup close (add mode, not confirmed):** when `isEdit` is false and `isSuccess` is false, refresh the events array - this strips the temporary event Mobiscroll placed on the calendar.
- **"Add" button:** build the event from form state (`getEventData()`), append to the events array, set `isSuccess = true`, call `calendar.navigateToEvent(newEvent)`, close popup.
- **"Save" button:** build updated event from form state, find by `id` and splice in place, call `calendar.navigateToEvent(updatedEvent)`, close popup.
- The popup form contains: **Title** (`Input`), **Description** (`Textarea`), **All-day** (`Switch` - when on, switches the date picker to date-only controls and removes the Travel time dropdown from the DOM; when off, restores both), **Start/End** (a `Datepicker` in range mode with `startInput`/`endInput` pointing to two separate `Input` fields; controls are `['datetime']` normally, `['date']` when all-day; on medium+ screens uses anchored calendar+time picker with `touchUi: false`), **Travel time** (`Dropdown` bound to `bufferBefore` in minutes: None/5/15/30 min/1 h/1.5 h/2 h - hidden when all-day is on), **Color** (a clickable row with a filled circle showing the current event color; clicking opens the color picker popup anchored to that element), **Show as busy / Show as free** (`SegmentedGroup` with `value="busy"`/`value="free"`, maps to the `free` boolean via `free: statusValue === 'free'`), and a **Delete event** button (danger/outline, visible in edit mode only).
- The color picker is a separate `Popup` with 10 color swatches in 2 rows of 5: `#ffeb3c`, `#ff9900`, `#f44437`, `#ea1e63`, `#9c26b0` / `#3f51b5`, empty string (no color), `#009788`, `#4baf4f`, `#7e5d4e`. Each swatch is a `div` with `data-value`. On desktop (`display: 'anchored'`, no buttons): clicking applies and closes immediately. On mobile: bottom-sheet with "Set"/"Cancel" - "Set" applies `selectedColor`. The active swatch is highlighted with the `mds-crud-color-value-selected` CSS class.
- **Delete from popup:** filter the event from the array by `id`, close the popup, show a snackbar ("Event deleted") with "Undo" that re-adds the event.

## 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-jquery.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 jquery
   ```

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 jquery --trial`.

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

## Related demos

- Next: [Block Past Event Creation](https://demo.mobiscroll.com/jquery/timeline/disallow-past-event-creation.md) - Keep past dates read-only on a JQuery resource timeline — block creation, moving, and resizing, and show a toast for blocked actions.
