Features

  • Highlights global holidays using custom grid cell background color + timeline bar

  • Highlights per-resource holidays using custom background color

  • Angular 20 application

  • Angular Scheduler from the open-source DayPilot Lite for JavaScript

Highlighting Global Holidays (Grid Cells)

Angular Scheduler (Open-Source) - Highlighting Global Holidays in Grid

DayPilot Angular Scheduler component lets you set custom background color for grid cells (see cell customization in the documentation). We will use this feature to highlight holidays. This sample only uses a custom background color - the drag and drop operations are not affected.

Lets have an array of holidays that we want to highlight:

export class SchedulerComponent implements AfterViewInit {

  // ...

  globalHolidays: any[] = [
    { start: '2026-09-15', end: '2026-09-15', backColor: '#fff2cc'}
  ];
  
  // ...

}

Each item in the array specifies the start and end dates and a background color to be applied.

We are using an all-day date format (start: "2026-09-15", end: "2026-09-15") instead of point-in-time format (start: "2026-09-15T00:00:00", end: "2026-09-16T00:00:00"). In case of holiday dates, this approach is more natural. However, since DayPilot works with exact date/time points internally we need to convert the end date manually (see below). See also Event End Date/Time topic in the documentation for more details.

Now we have the holiday dates defined so we can use the data to highlight the background cells using onBeforeCellRender event handler.

onBeforeCellRender: args => {
  const dp = this.scheduler.control;
  const component = this;

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

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

}

The event handler is fired for every grid cell. It searches the array with holiday definitions (globalHolidays) for items that overlap with the current cell. The first item that matches is used to set the cell background color (args.cell.backColor).

Source code (scheduler.component.ts):

import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "@daypilot/daypilot-lite-angular";
import {DataService} from "./data.service";

@Component({
  selector: 'scheduler-component',
  template: `<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>`,
  imports: [ DayPilotModule ],
  providers: [ DataService ],
  styles: [``]
})
export class SchedulerComponent implements AfterViewInit {

  @ViewChild("scheduler")
  scheduler!: DayPilotSchedulerComponent;

  events: any[] = [];

  globalHolidays: any[] = [
    { start: "2026-09-15", end: "2026-09-15", backColor: "#fff2cc", headerColor: "#f1c232"}
  ];

  config: DayPilot.SchedulerConfig = {
  
    // ...
  
    onBeforeCellRender: args => {
      const dp = this.scheduler.control;
      const component = this;

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

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

    }

  };
  
  // ...

}

Highlighting Global Holidays (Time Header)

Angular Scheduler (Open-Source) - Highlighting Global Holidays in Time Header

Another option to display the global holidays is to add a color bar to the Scheduler time header.

The time header cells can be customized using a similar approach. There is a onBeforeTimeHeaderRender event handler which is fired for every cell in the time header. See also time header customization in the documentation.

onBeforeTimeHeaderRender: args => {
  const component = this;

  if (args.header.level === 1) {
    const item = component.globalHolidays.find((range: any) => {
      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}
      ];
    }
  }
}

Our event handler searches the globalHolidays for an item that overlaps with the current cell. Note that only the cells in the second row are tested (args.header.level === 1).

If an overlapping record is found we insert an active area with the specified background color at the bottom of the time header cell.

Source code (scheduler.component.ts):

import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "@daypilot/daypilot-lite-angular";
import {DataService} from "./data.service";

@Component({
  selector: 'scheduler-component',
  template: `<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>`,
  imports: [ DayPilotModule ],
  providers: [ DataService ],
  styles: [``]
})
export class SchedulerComponent implements AfterViewInit {

  @ViewChild("scheduler")
  scheduler!: DayPilotSchedulerComponent;

  events: any[] = [];

  globalHolidays: any[] = [
    { start: "2026-09-15", end: "2026-09-15", backColor: "#fff2cc", headerColor: "#f1c232"}
  ];

  config: DayPilot.SchedulerConfig = {
    
    // ...
    
    onBeforeTimeHeaderRender: args => {
      const component = this;

      if (args.header.level === 1) {
        const item = component.globalHolidays.find((range: any) => {
          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}
          ];
        }
      }
    }
  };
  
  // ...

}

Highlighting Resource-Specific Holidays

Angular Scheduler (Open-Source) - Highlighting Resource-Specific Holidays

We can also highlight holidays that are specific to certain resources (rows). We will add the holiday definitions directly to the resources array of the config:

resources: [
  { name: "Resource 1", id: "R1", holidays: [
    { start: "2026-09-05", end: "2026-09-10", backColor: "#f4cccc"}
  ]},
  { name: "Resource 2", id: "R2", holidays: [
    { start: "2026-09-04", end: "2026-09-06", backColor: "#d9ead3"}
  ]},
  { 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"},
  { name: "Resource 10", id: "R10"},
]

The format is the same - each item specifies start, end and a background color. The end date of the holiday is specified as a date-only value.

We will use onBeforeCellRender event handler to find overlapping records. This time, we will only search the holiday records stored in the resource data:

onBeforeCellRender: args => {
  const dp = this.scheduler.control;
  const component = this;

  const row = dp.rows.find(args.cell.resource);
  const holidays = row.data.holidays;
  if (!holidays) {
    return;
  }
  const item = holidays.find((range: any) => {
    const start = new DayPilot.Date(range.start);
    const end = new DayPilot.Date(range.end).addDays(1);
    return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
  });

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

Source code (scheduler.component.ts):

import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "@daypilot/daypilot-lite-angular";
import {DataService} from "./data.service";

@Component({
  selector: 'scheduler-component',
  template: `<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>`,
  imports: [ DayPilotModule ],
  providers: [ DataService ],
  styles: [``]
})
export class SchedulerComponent implements AfterViewInit {

  @ViewChild("scheduler")
  scheduler!: DayPilotSchedulerComponent;

  events: any[] = [];

  config: DayPilot.SchedulerConfig = {
  
    // ...
  
    resources: [
      { name: "Resource 1", id: "R1", holidays: [
        { start: "2026-09-05", end: "2026-09-10", backColor: "#f4cccc"}
      ]},
      { name: "Resource 2", id: "R2", holidays: [
        { start: "2026-09-04", end: "2026-09-06", backColor: "#d9ead3"}
      ]},
      { 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"},
      { name: "Resource 10", id: "R10"},
    ],
    onBeforeCellRender: args => {
      const dp = this.scheduler.control;
      const component = this;

      const row = dp.rows.find(args.cell.resource);
      const holidays = row.data.holidays;
      if (!holidays) {
        return;
      }
      const item = holidays.find((range: any) => {
        const start = new DayPilot.Date(range.start);
        const end = new DayPilot.Date(range.end).addDays(1);
        return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
      });

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

  // ...

}

Source Code

Here is the full source code of our Angular Scheduler component that highlights global and resource-specific holidays. This file is also included in the download package with the Angular project (see the article header).

src/app/scheduler.component.ts

import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilot, DayPilotSchedulerComponent} from '@daypilot/daypilot-lite-angular';
import {DataService} from './data.service';
import {DayPilotModule} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'scheduler-component',
  template: `
    <daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>`,
  imports: [DayPilotModule],
  providers: [DataService],
  styles: [``]
})
export class SchedulerComponent implements AfterViewInit {

  @ViewChild('scheduler')
  scheduler!: DayPilotSchedulerComponent;

  events: any[] = [];

  globalHolidays: any[] = [
    {start: '2026-09-15', end: '2026-09-15', backColor: '#fff2cc', headerColor: '#f1c232'}
  ];

  config: DayPilot.SchedulerConfig = {
    timeHeaders: [{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}],
    scale: 'Day',
    days: 30,
    startDate: '2026-09-01',
    timeRangeSelectedHandling: 'Disabled',
    rowHeaderWidth: 100,
    durationBarVisible: false,
    eventBorderRadius: 5,
    resources: [
      {
        name: 'Resource 1', id: 'R1', holidays: [
          {start: '2026-09-05', end: '2026-09-10', backColor: '#f4cccc'}
        ]
      },
      {
        name: 'Resource 2', id: 'R2', holidays: [
          {start: '2026-09-04', end: '2026-09-06', backColor: '#d9ead3'}
        ]
      },
      {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'},
      {name: 'Resource 10', id: 'R10'},
    ],
    onBeforeCellRender: args => {
      const dp = this.scheduler.control;
      const component = this;

      (function applyResourceHolidays() {
        const row = dp.rows.find(args.cell.resource);
        const holidays = row.data.holidays;
        if (!holidays) {
          return;
        }
        const item = holidays.find((range: any) => {
          const start = new DayPilot.Date(range.start);
          const end = new DayPilot.Date(range.end).addDays(1);
          return DayPilot.Util.overlaps(start, end, args.cell.start, args.cell.end);
        });

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

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

        if (item) {
          args.cell.properties.backColor = item.backColor;
        }
      })();
    },
    onBeforeTimeHeaderRender: args => {
      const component = this;

      if (args.header.level === 1) {
        const item = component.globalHolidays.find((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) {
          args.header.areas = [
            {left: 0, right: 0, bottom: 0, height: 5, backColor: item.headerColor}
          ];
        }
      }
    },
    onBeforeEventRender: args => {
      args.data.backColor = "#3d85c6aa";
      args.data.fontColor = "white";
      args.data.borderColor = "darker";
    }

  };

  constructor(private ds: DataService) {
  }

  ngAfterViewInit(): void {

    const from = this.scheduler.control.visibleStart();
    const to = this.scheduler.control.visibleEnd();
    this.ds.getEvents(from, to).subscribe(result => {
      this.events = result;
    });
  }

}