Overview

In this Vue Scheduler tutorial, you will learn how to work with holidays:

  • How to define global and per-resource holidays.

  • How to display the holidays using custom Scheduler cell background color.

  • How to disable drag and drop for the holiday cells.

The attached project includes a trial version of DayPilot Pro for JavaScript (see License below).

For an introduction to using the Vue Scheduler component, please see the following tutorial:

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript.

How to display global holidays in Vue Scheduler?

How to display global holidays in Vue Scheduler

First, you need to define the global holidays. We will use a new globalHolidays property which holds an array with holiday dates. Each item specifies a date range, defined using start and end dates. The end date specifies the last day of the holiday (we need to take it into account later when checking the date range, see below).

The following example defines a holiday for August 9, 2021:

globalHolidays: [
  { start: "2025-08-09", end: "2025-08-09", backColor: "#b6d7a8", headerColor: "#6aa84f"}
],

Now you need to configure the Vue Scheduler component to highlight the grid cells that overlap any of the holiday date ranges.

You can customize the Vue Scheduler cells using onBeforeCellRender event handler. This event handler is called once for each of the Scheduler cells. You can use it to set custom background color and other properties.

In the event handler, we will check if the cell date (args.cell.start and args.cell.end) overlaps with the global holidays.

const start = new DayPilot.Date(holiday.start);
const end = new DayPilot.Date(holiday.end).addDays(1);
const overlaps = DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);

Note that we have added 1 day to the end date. The DayPilot.Util.overlaps() method works with exact time points. Our end date ("2025-08-09") is interpreted as the start of August 9, 2025 (ie. "2025-08-09T00:00:00"). In order to treat it as the end of August 9, 2025, you need to add one day using addDays(1). That will result in "2025-08-10T00:00:00", which is the time point we need.

If an overlap is detected, we set a custom background color using args.cell.backColor property.

The following code will highlight the holidays defined in the globalHolidays property:

<template>
  <DayPilotScheduler :config="config" ref="schedulerRef" />
</template>

<script setup>
import { ref, reactive } from 'vue';
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue';

const globalHolidays = ref([
  { start: "2025-08-09", end: "2025-08-09", backColor: "#b6d7a8", headerColor: "#6aa84f" }
]);

const config = reactive({
  onBeforeCellRender: (args) => {
    highlightGlobalHolidays(args);
  },
  // ...
});

const highlightGlobalHolidays = (args) => {
  const item = globalHolidays.value.find(holiday => {
    const start = new DayPilot.Date(holiday.start);
    const end = new DayPilot.Date(holiday.end).addDays(1);
    return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
  });

  if (item) {
    args.cell.backColor = item.backColor;
  }
};

const schedulerRef = ref(null);

// ...

</script>

How to highlight global holidays in the Vue Scheduler time header?

You can also highlight the global holidays in the Vue Scheduler time header. Note the green bar displayed in the time header cell for August 9, 2021:

How to highlight global holidays in the Vue Scheduler time header

To highlight the holidays in the time header, you can use the onBeforeTimeHeaderRender event handler, which lets you customize the appearance of the time headers cells.

The logic is very similar - you need to check for overlaps of the time header cell start and end with the global holiday dates.

This time, we will not highlight the whole cell using the backColor property but we will add a small bar at the bottom of the time header cell using active areas:

const config = reactive({
  onBeforeTimeHeaderRender: (args) => {
    if (args.header.level === 1) {
      const item = globalHolidays.value.find(function (range) {
        const start = new DayPilot.Date(range.start);
        const end = new DayPilot.Date(range.end).addDays(1);
        return DayPilot.Util.overlaps(start, end, args.header.start, args.header.end);
      });

      if (item) {
        const start = new DayPilot.Date(item.start);
        const end = new DayPilot.Date(item.end).addDays(1);

        args.header.areas = [
          {start: start, end: end, bottom: 0, height: 5, backColor: item.headerColor}
        ];
      }
    }
  },
  // ...
});

How to disable drag and drop operations for holidays?

How to disable drag and drop operations for holidays in Vue Scheduler

In the previous example, we have changed the background color of the Scheduler cells but we didn’t change the cell behavior.

If you want to disable the drag and drop operations for the cells marked as holidays, you need to use args.cell.disabled to mark the cell as disabled:

<template>
  <div class="space">
    <label><input type="checkbox" v-model="holidaysDisabled" @change="updateDisabled">Disable drag and drop for holidays</label>
  </div>
  <DayPilotScheduler :config="config" ref="schedulerRef" />
</template>

<script setup>
import { ref, reactive } from 'vue';
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue';

const holidaysDisabled = ref(true);
const globalHolidays = ref([
  { start: "2025-08-09", end: "2025-08-09", backColor: "#b6d7a8", headerColor: "#6aa84f" }
]);

const config = reactive({
  onBeforeCellRender: (args) => {
    highlightGlobalHolidays(args);
  }
});

const highlightGlobalHolidays = (args) => {
  // ...

  const item = globalHolidays.value.find(holiday => {
    const start = new DayPilot.Date(holiday.start);
    const end = new DayPilot.Date(holiday.end).addDays(1);
    return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
  });

  if (item) {
    // ...

    if (holidaysDisabled.value) {
      args.cell.disabled = true;
    }

  }
};

const updateDisabled = () => {
  schedulerRef.value.control.update();
};

const schedulerRef = ref(null);

</script>

How to display resource-specific holidays in the Vue Scheduler?

vue scheduler per resource holidays

You can also define holidays for specific resources. In this example, we define the holidays using a custom holidays property of the resources[] array:

const resources = [
  { name: "Resource A", id: "A"},
  { name: "Resource B", id: "B", holidays: [
      { start: "2025-08-04", end: "2025-08-06", backColor: "#dd7e6b"}
    ]},
  { name: "Resource C", id: "C"},
  { name: "Resource D", id: "D", holidays: [
      { start: "2025-08-02", end: "2025-08-06", backColor: "#ffe599"}
    ]},
  { name: "Resource E", id: "E"},
  { name: "Resource F", id: "F"},
  { name: "Resource G", id: "G"},
  { name: "Resource H", id: "H"},
  { name: "Resource I", id: "I"},
  { name: "Resource J", id: "J"},
];

Now, it’s necessary to check the overlaps with the resource holidays in onBeforeCellRender event handler.

First, you need to get the holiday data. The resource ID is available in args.cell.resource. To find the resource data object, use the rows.find() method:

const row = scheduler.rows.find(args.cell.resource);
const holidays = row.data.holidays;

The next step is to check for overlaps with the resource holiday dates:

<template>
  <DayPilotScheduler :config="config" ref="schedulerRef" />
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue';

const holidaysDisabled = ref(true);

const config = reactive({
  onBeforeCellRender: (args) => {
    // ...
    highlightResourceHolidays(args);
  }
});

const schedulerRef = ref(null);

const highlightResourceHolidays = (args) => {
  const row = schedulerRef.value.control.rows.find(args.cell.resource);
  const holidays = row.data.holidays;
  if (!holidays) {
    return;
  }
  const item = holidays.find(holiday => {
    const start = new DayPilot.Date(holiday.start);
    const end = new DayPilot.Date(holiday.end).addDays(1);
    return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
  });

  if (item) {
    args.cell.backColor = item.backColor;

    if (holidaysDisabled.value) {
      args.cell.disabled = true;
    }
  }
};

const loadResources = () => {
  const resources = [
    { name: "Resource A", id: "A" },
    { name: "Resource B", id: "B", holidays: [
        { start: "2025-08-04", end: "2025-08-06", backColor: "#dd7e6b" }
      ] },
    { name: "Resource C", id: "C" },
    { name: "Resource D", id: "D", holidays: [
        { start: "2025-08-02", end: "2025-08-06", backColor: "#ffe599" }
      ] },
    { name: "Resource E", id: "E" },
    { name: "Resource F", id: "F" },
    { name: "Resource G", id: "G" },
    { name: "Resource H", id: "H" },
    { name: "Resource I", id: "I" },
    { name: "Resource J", id: "J" },
  ];
  config.resources = resources;
};


onMounted(() => {
  loadResources();
});
</script>

Full Source Code

And here is the full source code for the Vue Scheduler example which highlights global and resource-specific holidays in the Scheduler grid, with an option to disable drag and drop for the holidays.

<template>
  <div class="space">
    <label><input type="checkbox" v-model="holidaysDisabled" @change="updateDisabled">Disable drag and drop for holidays</label>
  </div>
  <DayPilotScheduler :config="config" ref="schedulerRef" />
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue';

const holidaysDisabled = ref(false);
const globalHolidays = ref([
  { start: "2025-08-09", end: "2025-08-09", backColor: "#b6d7a8", headerColor: "#6aa84f" }
]);

const schedulerRef = ref(null);

const config = reactive({
  timeHeaders: [{ "groupBy": "Month" }, { "groupBy": "Day", "format": "d" }],
  scale: "Day",
  startDate: "2025-08-01",
  days: 31,
  timeRangeSelectedHandling: "Enabled",
  durationBarVisible: false,
  onTimeRangeSelected: async (args) => {
    const scheduler = args.control;
    const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
    scheduler.clearSelection();
    if (modal.canceled) {
      return;
    }
    scheduler.events.add({
      start: args.start,
      end: args.end,
      id: DayPilot.guid(),
      resource: args.resource,
      text: modal.result
    });
  },
  treeEnabled: true,
  onBeforeTimeHeaderRender: (args) => {
    if (args.header.level === 1) {
      const item = globalHolidays.value.find(function (range) {
        const start = new DayPilot.Date(range.start);
        const end = new DayPilot.Date(range.end).addDays(1);
        return DayPilot.Util.overlaps(start, end, args.header.start, args.header.end);
      });

      if (item) {
        const start = new DayPilot.Date(item.start);
        const end = new DayPilot.Date(item.end).addDays(1);

        args.header.areas = [
          {start: start, end: end, bottom: 0, height: 5, backColor: item.headerColor}
        ];
      }
    }
  },
  onBeforeCellRender: (args) => {
    // highlightResourceHolidays(args);
    highlightGlobalHolidays(args);
  }
});

const updateDisabled = () => {
  schedulerRef.value.control.update();
};

const highlightGlobalHolidays = (args) => {
  const item = globalHolidays.value.find(holiday => {
    const start = new DayPilot.Date(holiday.start);
    const end = new DayPilot.Date(holiday.end).addDays(1);
    return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
  });

  if (item) {
    args.cell.backColor = item.backColor;

    if (holidaysDisabled.value) {
      args.cell.disabled = true;
    }
  }
};

const highlightResourceHolidays = (args) => {
  const scheduler = args.control;
  const row = scheduler.rows.find(args.cell.resource);
  const holidays = row.data.holidays;
  if (!holidays) {
    return;
  }
  const item = holidays.find(holiday => {
    const start = new DayPilot.Date(holiday.start);
    const end = new DayPilot.Date(holiday.end).addDays(1);
    return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
  });

  if (item) {
    args.cell.backColor = item.backColor;

    if (holidaysDisabled.value) {
      args.cell.disabled = true;
    }
  }
};

const loadEvents = () => {
  const events = [
    {id: 1, start: "2025-08-01T00:00:00", end: "2025-08-05T00:00:00", text: "Event 1", resource: "R1"},
  ];
  config.events = events;
};

const loadResources = () => {
  const resources = [
    {name: "Resource A", id: "A"},
    {
      name: "Resource B", id: "B", holidays: [
        {start: "2025-08-04", end: "2025-08-06", backColor: "#dd7e6b"}
      ]
    },
    {name: "Resource C", id: "C"},
    {
      name: "Resource D", id: "D", holidays: [
        {start: "2025-08-02", end: "2025-08-06", backColor: "#ffe599"}
      ]
    },
    {name: "Resource E", id: "E"},
    {name: "Resource F", id: "F"},
    {name: "Resource G", id: "G"},
    {name: "Resource H", id: "H"},
    {name: "Resource I", id: "I"},
    {name: "Resource J", id: "J"},
  ];
  config.resources = resources;
};

onMounted(() => {
  loadResources();
  loadEvents();

  schedulerRef.value?.control.message("Welcome!");
});
</script>


<style>
.scheduler_default_event,
.scheduler_default_event_inner {
  border-radius: 25px;
}

body .scheduler_default_event_inner {
  background: #42a5f5;
  color: #ffffff;
  border: 1px solid #1e88e5;
  padding-left: 10px;
}
</style>

You can download a complete Vue 3 project at the top of the article.