Overview

  • Define custom JavaScript Scheduler event types

  • Customize the appearance depending on event type

  • Change event type using a context menu

  • Change event type using a modal dialog

License

This tutorial uses the open-source DayPilot Lite for JavaScript scheduling library.

Storing Event Type

The best place to store the event type (we are going to use type property) is the tags property of the event data object. Storing custom data under tags avoids future conflicts with the reserved property names at the top level.

const events = [
  {
    id: 1,
    text: "Event 1",
    start: "2026-03-05T00:00:00",
    end: "2026-03-09T00:00:00",
    resource: "R2",
    tags: {
      type: "standard"
    }
  },
  {
    id: 2,
    text: "Event 2",
    start: "2026-03-07T00:00:00",
    end: "2026-03-15T00:00:00",
    resource: "R4",
    tags: {
      type: "important"
    }
  },
];

Appearance of Event Types

JavaScript Scheduler - Appearance of Event Types

Now we need to define the appearance for the different event types. This can be done using onBeforeEventRender event handler. In this example, we use a custom background color (backColor property) but you can add your own text/HTML, icons, CSS classes and so on.

onBeforeEventRender: args => {
  const type = args.data.tags?.type;
  switch (type) {
    case "standard":
      args.data.backColor = "#6aa84faa";
      args.data.fontColor = "#fff";
      break;
    case "important":
      args.data.backColor = "#f18832aa";
      args.data.fontColor = "#fff";
      break;
  }
  args.data.borderColor = "darker";
}

Changing Event Type using Context Menu

JavaScript Scheduler - Changing Event Type using Context Menu

In this step, we will add an option to change the Scheduler event type using context menu. The context menu will display all event types and the current one will be highlighted using a checkmark icon.

Normally, the context menu items are pre-defined using the items property. But we need to generate the items from the list of event types and highlight the current type. We will use onShow event to modify the context menu items right before the menu is displayed:

contextMenu: new DayPilot.Menu({
  items: [],
  onShow: args => {
    const e = args.source;

    // generate menu items dynamically
    scheduler.contextMenu.items = [
      {text: "Edit...", onClick: async args =>  app.edit(args.source) },
      {text: "-"}
    ];
    app.types.forEach(type => {
      const item = {
        text: type.name,
        onClick: args => app.changeType(args.source, type.id)
      };
      if (type.id === e.data.tags.type) {
        item.symbol = "/icons/daypilot.svg#checkmark-2";
      }
      scheduler.contextMenu.items.push(item);
    });
  }
})

The changeType() function changes the event data object and calls events.update() to apply the changes:

changeType(e, type) {
  e.data.tags.type = type;
  scheduler.events.update(e);
},

Changing Event Type using Modal Dialog

JavaScript Scheduler - Edit Event Type using Modal Dialog

First, we will configure the Scheduler to display a modal dialog with event details on click:

onEventClick: async args => app.edit(args.e),

The edit() function opens a modal dialog using DayPilot.Modal.form(). You can design a custom modal dialog using DayPilot Modal Builder.

The modal form fields are mapped directly to the event data object (text ang tags.type properties).

const app = {
  get form() {
    return [
      { name: "Event name", id: "text" },
      { name: "Event type", id: "tags.type", type: "select", options: this.types },
    ];
  },
  types: [
    {name: "Standard", id: "standard"},
    {name: "Important", id: "important"},
  ],
  async edit(e) {
    const modal = await DayPilot.Modal.form(app.form, e.data);
    if (modal.canceled) {
      return;
    }
    scheduler.events.update(modal.result);
  },
  // ...
};

Full Source Code

And here is the full source code of the JavaScript Scheduler component displaying custom event types:

import {DayPilot} from "@daypilot/daypilot-lite-javascript";

const scheduler = new DayPilot.Scheduler("scheduler", {
  timeHeaders: [{groupBy: "Month"}, {groupBy: "Day", format: "d"}],
  scale: "Day",
  days: 31,
  startDate: "2026-03-01",
  eventBorderRadius: 20,
  durationBarVisible: false,
  eventPadding: 10,
  onTimeRangeSelected: async args => {
    const data = {
      text: "Event 1",
      start: args.start,
      end: args.end,
      resource: args.resource,
      id: DayPilot.guid(),
      tags: {
        type: "standard"
      }
    };
    const modal = await DayPilot.Modal.form(app.form, data);
    scheduler.clearSelection();
    if (modal.canceled) { return; }
    scheduler.events.add(modal.result);
  },
  onEventClick: async args => app.edit(args.e),
  onBeforeEventRender: args => {
    const type = args.data.tags?.type;
    switch (type) {
      case "standard":
        args.data.backColor = "#6aa84faa";
        args.data.fontColor = "#fff";
        break;
      case "important":
        args.data.backColor = "#f18832aa";
        args.data.fontColor = "#fff";
        break;
    }
    args.data.borderColor = "darker";

    args.data.areas = [
      {
        right: 6,
        top: 6,
        height: 24,
        width: 24,
        symbol: "/icons/daypilot.svg#minichevron-down-2",
        action: "ContextMenu",
        padding: 2,
        fontColor: "#666",
        backColor: "#ffffffdd",
        borderRadius: "50%"
      }
    ]
  },
  contextMenu: new DayPilot.Menu({
    items: [],
    onShow: args => {
      const e = args.source;

      // generate menu items dynamically
      scheduler.contextMenu.items = [
        {text: "Edit...", onClick: async args =>  app.edit(args.source) },
        {text: "-"}
      ];
      app.types.forEach(type => {
        const item = {
          text: type.name,
          onClick: args => app.changeType(args.source, type.id)
        };
        if (type.id === e.data.tags.type) {
          item.symbol = "/icons/daypilot.svg#checkmark-2";
        }
        scheduler.contextMenu.items.push(item);
      });
    }
  }),
});
scheduler.init();

const app = {
  get form() {
    return [
      { name: "Event name", id: "text" },
      { name: "Event type", id: "tags.type", type: "select", options: this.types },
    ];
  },
  types: [
    {name: "Standard", id: "standard"},
    {name: "Important", id: "important"},
  ],
  async edit(e) {
    const modal = await DayPilot.Modal.form(app.form, e.data);
    if (modal.canceled) {
      return;
    }
    scheduler.events.update(modal.result);
  },
  changeType(e, type) {
    e.data.tags.type = type;
    scheduler.events.update(e);
  },
  init() {
    const events = [
      {
        id: 1,
        text: "Event 1",
        start: "2026-03-05T00:00:00",
        end: "2026-03-09T00:00:00",
        resource: "R2",
        tags: {
          type: "standard"
        }
      },
      {
        id: 2,
        text: "Event 2",
        start: "2026-03-07T00:00:00",
        end: "2026-03-15T00:00:00",
        resource: "R4",
        tags: {
          type: "important"
        }
      },
    ];
    const resources = [
      {name: "Resource 1", id: "R1"},
      {name: "Resource 2", id: "R2"},
      {name: "Resource 3", id: "R3"},
      {name: "Resource 4", id: "R4"},
      {name: "Resource 5", id: "R5"},
      {name: "Resource 6", id: "R6"},
      {name: "Resource 7", id: "R7"},
      {name: "Resource 8", id: "R8"},
      {name: "Resource 9", id: "R9"},
    ];

    scheduler.update({resources, events});
  }
};
app.init();