The JavaScript Monthly Calendar component supports creating events by dragging items from an external list and dropping them onto a day cell.

This is useful when you have a list of unscheduled items outside of the calendar and you want users to assign them to dates using drag and drop.

Activating External Items

Use the static DayPilot.Month.makeDraggable() method to activate an external DOM element as a drag source.

Call the method using the full DayPilot.Month.makeDraggable() prefix. It is a static method and it is not called on a DayPilot.Month instance.

<div id="external">
  <div class="external-item" data-id="123" data-days="1">Item #123 (1 day)</div>
  <div class="external-item" data-id="124" data-days="2">Item #124 (2 days)</div>
</div>

<div id="dp"></div>

<script>
  const month = new DayPilot.Month("dp", {
    onEventMove: args => {
      if (args.external) {
        console.log("External item dropped:");
        console.log("Event data:", args.e.data);
        console.log("Start:", args.newStart);
        console.log("End:", args.newEnd);
      }
    }
  });
  month.init();

  const items = document.querySelectorAll("#external .external-item");

  items.forEach(element => {
    const days = parseInt(element.dataset.days, 10);

    DayPilot.Month.makeDraggable({
      element: element,
      data: {
        id: element.dataset.id,
        text: element.innerText,
        duration: DayPilot.Duration.ofDays(days)
      }
    });
  });
</script>

The data object defines the event that will be created when the item is dropped onto the Monthly Calendar.

The following properties are recognized:

  • id: Event ID.

  • text: Event text.

  • duration: Event duration. You can use a number of seconds or a DayPilot.Duration object.

For Month events that span one or more full days, using DayPilot.Duration.ofDays() is recommended:

DayPilot.Month.makeDraggable({
  element: element,
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

If you use a numeric value for duration, specify the value in seconds:

DayPilot.Month.makeDraggable({
  element: element,
  data: {
    id: "123",
    text: "Item #123",
    duration: 24 * 60 * 60
  }
});

Any additional properties of the data object are copied to the event data object on drop.

DayPilot.Month.makeDraggable({
  element: element,
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1),
    type: "task",
    priority: "high"
  }
});

Keeping the Source Element

By default, the source element is removed from the DOM when it is dropped on the Monthly Calendar.

Use keepElement: true to keep the original element in the external list after drop:

DayPilot.Month.makeDraggable({
  element: element,
  keepElement: true,
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

You can also use the remove option to specify a different DOM node that should be removed on drop.

This is useful when the draggable element is only a handle and you want to remove the whole list item:

const item = document.querySelector("#item-123");
const handle = item.querySelector(".drag-handle");

DayPilot.Month.makeDraggable({
  element: handle,
  remove: item,
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

Handling the Drop

When an external item is dropped onto the Monthly Calendar, DayPilot fires the standard event moving handler, onEventMove.

Use args.external to detect that the event was created from an external drag source:

const month = new DayPilot.Month("dp", {
  onEventMove: args => {
    if (!args.external) {
      return;
    }

    const data = {
      id: args.e.data.id,
      text: args.e.data.text,
      start: args.newStart,
      end: args.newEnd
    };

    console.log("Saving external drop:", data);
  }
});
month.init();

The onEventMove handler is fired before the default action configured using eventMoveHandling.

The default value of eventMoveHandling is "Update", which updates the event position on the client side.

const month = new DayPilot.Month("dp", {
  eventMoveHandling: "Update",
  onEventMove: args => {
    if (args.external) {
      console.log("External item dropped.");
    }
  }
});
month.init();

Use args.preventDefault() to cancel the drop.

const month = new DayPilot.Month("dp", {
  onEventMove: args => {
    if (args.external && !isDropAllowed(args.newStart, args.newEnd)) {
      args.preventDefault();
      args.control.message("This item cannot be scheduled here.");
    }
  }
});
month.init();

function isDropAllowed(start, end) {
  // Add your validation rules here.
  return true;
}

Customizing the Drag Shadow

You can customize the appearance of the moving shadow while the item is outside of the Month component.

DayPilot.Month.makeDraggable({
  element: element,
  externalCssClass: "external-shadow",
  externalHtml: element.innerText,
  externalCursor: "move",
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

Options:

  • externalCssClass: CSS class applied to the moving shadow while it is outside of the Month component.

  • externalHtml: HTML displayed in the moving shadow while it is outside of the Month component.

  • externalCursor: CSS cursor used during external drag and drop.

Example CSS:

.external-shadow {
  padding: 4px 8px;
  border: 1px solid #999;
  background: #fff;
  box-shadow: 0 2px 4px #999;
}

Drag Start and Drop Callbacks

The DayPilot.Month.makeDraggable() options include onDragStart and onDrop callbacks.

Use onDragStart to cancel dragging before it starts:

DayPilot.Month.makeDraggable({
  element: element,
  onDragStart: args => {
    if (element.classList.contains("disabled")) {
      args.preventDefault();
    }
  },
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

Use onDrop to run custom logic when the external item is dropped:

DayPilot.Month.makeDraggable({
  element: element,
  onDrop: args => {
    console.log("Dropped:", args.options.data);
  },
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

Multiple Calendar Targets

External drag and drop supports using Calendar and Month component targets on the same page.

This means that the same external item list can be used with a page that contains both a DayPilot.Calendar and a DayPilot.Month target.

Use the target component’s static makeDraggable() method for the component you want to support:

DayPilot.Month.makeDraggable({
  element: element,
  data: {
    id: "123",
    text: "Item #123",
    duration: DayPilot.Duration.ofDays(1)
  }
});

Touch Devices

External drag and drop for the Monthly Calendar supports touch devices. Available since version 2026.3.6967.