DayPilot Angular Calendar displays events on a vertical time axis, with columns for days or resources. A week view shows appointments across seven days; a resource view compares the schedules of several people or rooms on the same date. Users can select a time range, move an event to another column, or resize it to change its duration.

The component is available in DayPilot Lite, the open-source edition under the Apache License 2.0, and DayPilot Pro, the commercial edition with additional scheduling features. Both provide Angular components, TypeScript definitions, and bindings for configuration and event data.

Try the Angular calendar demo · Get the starter project · Configure a calendar in UI Builder

Angular Event Calendar Component (DayPilot)

Angular Calendar Features

The day and week layouts work well when users need to see the timing and duration of appointments. A resource calendar uses the same vertical time axis to compare bookings for several people, rooms, or machines side by side.

DayPilot Lite and Pro

  • Day, work-week, week, and custom day views. Choose the calendar view and number of days to display. Combine Calendar with the Angular monthly calendar when your application needs a month overview as well.

  • Resources as columns. Display a daily schedule for staff, rooms, or equipment using the resource calendar. Each event belongs to a resource column, and users can move it to a different resource.

  • Interactive event editing. Let users select a time range to create an event, then move or resize it using drag and drop. Handle these actions in Angular callbacks to open an editor, update your application state, and save changes to your backend.

  • Event appearance and CSS themes. Use colors, labels, and event actions to make different types of appointments easy to recognize. Event customization, cell customization, and CSS themes let you adapt the calendar to your application.

  • Working hours and date formatting. Set business hours, time-slot duration, and the first day of the week. Use a locale to format dates and times for your users.

  • Date navigation and Angular state. Connect an Angular date picker, add previous/next buttons, and load events for the selected period. Bind options and event data using signals or ordinary objects and arrays.

Additional DayPilot Pro Features

The Pro demos above show the underlying JavaScript Calendar features that you can configure through the Angular component. For the complete edition comparison, see the feature matrix. If you need time to run horizontally with resources as rows, see the Angular Scheduler.

Angular Calendar Examples

Undo and Redo Calendar Edits (Lite)

Calendar callbacks let an Angular application respond to individual edits and keep a history of changes. The undo/redo tutorial records event creation, movement, resizing, and deletion in an application service. Each record stores the event's previous and current data, so Undo can restore the previous dates or bring back a deleted event. Redo applies the recorded change again.

The service starts with a snapshot of the loaded events and controls whether the Undo and Redo buttons are enabled. The Calendar supplies the editing callbacks and event add/update/remove methods; the tutorial supplies the history and replay logic. In the live demo, move the sample event, undo the move, and redo it to see the event and history position change together.

The tutorial keeps the action history in an Angular service and updates the Calendar when an action is undone or redone.

Combine Text and Event-Type Filters (Pro)

The event-filtering example combines a case-insensitive text search with a Reservation/Maintenance selector. An event stays visible only when it matches both criteria. For example, choosing Maintenance and entering part of an event name narrows the view to maintenance events with that text.

The Angular controls pass the criteria to events.filter(); onEventFilter applies the application's matching rules to each event. The custom type field also controls event color and the Maintenance label. Clearing the filters restores the loaded events without fetching or recreating them. Try the combined filters.

Angular Calendar Demos and Tutorials

Explore the live examples before adding the component to your application. Each tutorial explains the implementation and provides a downloadable Angular project. The edition is shown for each example so you can start with the package you plan to use.

Calendar Views and Date Navigation

Editing, Appearance, and Layout

Backend Integration and Specialized Schedules

  • Angular Appointment Calendar with PHP/MySQL (Lite)
    Load appointments and save creation, edits, moves, and deletion through a PHP API. The current project uses standalone Angular components and signals, with SQLite or MySQL storage.

  • Angular Timetable (Pro)
    Build a weekly timetable with custom time blocks and labels. The tutorial uses an older Angular project structure but illustrates a specialized Calendar layout.

  • Angular Calendar: Displaying a Custom Set of Days (Pro)
    Display a selected set of dates as columns, including non-consecutive dates. This example uses an older Angular project structure; the column configuration is the main pattern to reuse.

Configure an Angular Calendar Visually

calendar ui builder configurator

Calendar UI Builder lets you change the calendar's appearance and behavior while seeing the result immediately. Select an Angular target and the edition you want to use, then download a starter project with your configuration. You can continue editing the options in TypeScript after downloading the project.

Installation

DayPilot Lite

Install @daypilot/daypilot-lite-angular from npm:

npm install @daypilot/daypilot-lite-angular

DayPilot Pro

At npm.daypilot.org, select Angular and copy the installation command for daypilot-pro-angular. Licensed customers can obtain their package URL in the customer area.

The examples use standalone Angular components. Import DayPilotModule in the component that contains the DayPilot tag.

Display a Weekly Appointment Calendar

Start with a Monday-first week and one two-hour meeting.

calendar.component.ts

import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <daypilot-calendar
      [config]="config"
      [events]="events"></daypilot-calendar>
  `
})
export class CalendarComponent {
  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week',
    weekStarts: 1
  };

  events: DayPilot.EventData[] = [
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ];
}

viewType: "Week" displays a week containing startDate. weekStarts: 1 makes Monday the first column. Events use a unique id, display text, and start/end date-times. The meeting ends at 12:00; event ends are exclusive.

Import CalendarComponent in the parent component and use <app-calendar></app-calendar> in its template.

The examples use Lite. For Pro, change the package import to daypilot-pro-angular.

See event loading for data formats and loading options.

Navigate and Load Appointments

Previous and Next move by one week. Request appointments for that week, then replace the bound event array with the JSON array returned by your backend.

calendar-loading.component.ts

import {Component, ChangeDetectorRef, inject, OnInit} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <button (click)="navigate(-1)">Previous week</button>
    <button (click)="navigate(1)">Next week</button>
    <daypilot-calendar
      [config]="config"
      [events]="events"></daypilot-calendar>
  `
})
export class CalendarComponent implements OnInit {
  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week',
    weekStarts: 1
  };

  events: DayPilot.EventData[] = [];

  private changes = inject(ChangeDetectorRef);

  private loadRequest = 0;

  ngOnInit() {
    this.loadData();
  }

  navigate(offset: number) {
    const start = new DayPilot.Date(this.config.startDate!).addDays(offset * 7);
    this.config = {...this.config, startDate: start};
    this.loadData();
  }

  async loadData() {
    const request = ++this.loadRequest;
    const start = new DayPilot.Date(this.config.startDate!);
    const end = start.addDays(7);
    const url = `/api/events?start=${start}&end=${end}`;
    try {
      const {data} = await DayPilot.Http.get(url);
      if (request !== this.loadRequest) { return; }
      this.events = data;
      this.changes.markForCheck();
    } catch {
      if (request === this.loadRequest) {
        await DayPilot.Modal.alert('Could not load data.');
      }
    }
  }
}

The /api/events URL represents your own backend. Return items that overlap the requested range: item start is before the requested end, and item end is after the requested start. Failed requests display a DayPilot dialog.

The request counter prevents an older response from replacing data after another navigation action.

Create Appointments by Selecting Time

This complete variation of the first example handles time range selection. The selection supplies the dates; the dialog supplies the name.

calendar-creation.component.ts

import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <daypilot-calendar
      [config]="config"
      [events]="events"></daypilot-calendar>
  `
})
export class CalendarComponent {
  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week',
    weekStarts: 1,
    onTimeRangeSelected: async args => {
      const modal = await DayPilot.Modal.prompt('Appointment name:', 'New appointment');
      args.control.clearSelection();
      if (modal.canceled) { return; }
      args.control.events.add({
        id: DayPilot.guid(), text: modal.result,
        start: args.start, end: args.end
      });
    }
  };

  events: DayPilot.EventData[] = [
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ];
}

Canceling the dialog leaves the data unchanged. events.add() inserts the new event locally. In an application with a backend, create the record with a POST request and use the returned ID before adding it to the view.

Move, Resize and Save Events

Moving changes the event position; resizing changes its duration. Both work in the first example without extra configuration. The component updates the display and the supplied data object automatically.

Use the callbacks after the edit to persist the result. This example sends the changed record to the backend; it does not reload the collection after each drag.

calendar-saving.component.ts

import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <daypilot-calendar
      [config]="config"
      [events]="events"></daypilot-calendar>
  `
})
export class CalendarComponent {
  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week',
    weekStarts: 1,
    onEventMoved: args => this.saveEvent(args.e.data),
    onEventResized: args => this.saveEvent(args.e.data)
  };

  events: DayPilot.EventData[] = [
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ];

  async saveEvent(data: DayPilot.EventData) {
    try {
      await DayPilot.Http.put(`/api/events/${data.id}`, data);
    } catch {
      await DayPilot.Modal.alert('The change could not be saved.');
    }
  }
}

The /api/events/{id} endpoint accepts the updated JSON record. A failed save is reported while the local edit remains visible; add retry or rollback behavior to suit your application. To disable an interaction, set eventMoveHandling or eventResizeHandling to "Disabled".

Handle a Event Click

To display the clicked item’s name, add this callback to config:

onEventClick: args => DayPilot.Modal.alert(DayPilot.Util.escapeHtml(args.e.text()))

DayPilot.Modal.alert() accepts HTML. escapeHtml() displays the item’s name as plain text.

Access the Calendar API

Use the event collection API to find and rename the meeting. The wrapper reference, button and handler are shown together.

calendar-api.component.ts

import {Component, ViewChild} from '@angular/core';
import {
  DayPilot, DayPilotModule, DayPilotCalendarComponent
} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <button (click)="renameEvent()">Rename meeting</button>
    <daypilot-calendar
      #calendar
      [config]="config"
      [events]="events"></daypilot-calendar>
  `
})
export class CalendarComponent {
  @ViewChild('calendar') calendar!: DayPilotCalendarComponent;

  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week',
    weekStarts: 1
  };

  events: DayPilot.EventData[] = [
    {id: 'meeting', text: 'Meeting',
      start: '2026-10-05T10:00:00', end: '2026-10-05T12:00:00'}
  ];

  async renameEvent() {
    const control = this.calendar.control;
    const event = control.events.find('meeting');
    const modal = await DayPilot.Modal.prompt('Event name:', event.text());
    if (modal.canceled) { return; }
    event.text(modal.result);
    control.events.update(event);
  }
}

@ViewChild provides the wrapper; its control property exposes the underlying JavaScript component after initialization. The wrapper creates and disposes it. See the DayPilot.Calendar API for methods, properties and callbacks.

Load Data into Signal Inputs

If your application stores the collection in an Angular signal, pass that signal to the same input. This standalone variation loads data and calls set(); the wrapper observes the new collection.

calendar-signal-loading.component.ts

import {Component, OnInit, signal} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <button (click)="navigate(-1)">Previous week</button>
    <button (click)="navigate(1)">Next week</button>
    <daypilot-calendar
      [config]="config"
      [events]="events"></daypilot-calendar>
  `
})
export class CalendarComponent implements OnInit {
  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week',
    weekStarts: 1
  };

  events = signal<DayPilot.EventData[]>([]);

  private loadRequest = 0;

  ngOnInit() {
    this.loadData();
  }

  navigate(offset: number) {
    const start = new DayPilot.Date(this.config.startDate!).addDays(offset * 7);
    this.config = {...this.config, startDate: start};
    this.loadData();
  }

  async loadData() {
    const request = ++this.loadRequest;
    const start = new DayPilot.Date(this.config.startDate!);
    const end = start.addDays(7);
    const url = `/api/events?start=${start}&end=${end}`;
    try {
      const {data} = await DayPilot.Http.get(url);
      if (request !== this.loadRequest) { return; }
      this.events.set(data);
    } catch {
      if (request === this.loadRequest) {
        await DayPilot.Modal.alert('Could not load data.');
      }
    }
  }
}

Bind the signal itself with [events]="events". Binding its current value with () instead uses the ordinary input path. Keep one form consistently. Signals require Angular 16 or later.

Signal configuration/event inputs are supported since DayPilot Pro 2025.1.6377 and DayPilot Lite Angular 5.0.0.

Customize Content with Angular Templates (Pro)

Use Angular markup for Calendar events, time cells, column headers, and time headers. Each template receives the item being rendered, so it can show appointment details or custom labels using Angular bindings.

This template integration is available in DayPilot Pro for Angular since version 2026.4.7099. Install the corresponding daypilot-pro-angular package from npm.daypilot.org.

Import DayPilotModule from daypilot-pro-angular in the Angular component that owns the template. It exports the DayPilot component and the daypilotTemplate directive. Place a named ng-template directly inside <daypilot-calendar>. Templates support Angular interpolation, bindings, event handlers, and child components; import any child components or additional Angular directives you use in the containing component.

Template Example

This standalone example supplies the component configuration and data as well as the template markup.

import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from 'daypilot-pro-angular';

@Component({
  selector: 'app-calendar-templates',
  standalone: true,
  imports: [DayPilotModule],
  template: `
    <daypilot-calendar [config]="config" [events]="events">
      <ng-template daypilotTemplate="event"
                   daypilotTemplateFor="calendar" let-event="event">
        <strong>{{ event.text() }}</strong>
      </ng-template>
      <ng-template daypilotTemplate="cell"
                   daypilotTemplateFor="calendar" let-cell="cell">
        <small>{{ cell.start.toString('H:mm') }}</small>
      </ng-template>
      <ng-template daypilotTemplate="columnHeader"
                   daypilotTemplateFor="calendar" let-column="column">
        <strong>{{ column.name }}</strong>
      </ng-template>
      <ng-template daypilotTemplate="timeHeader"
                   daypilotTemplateFor="calendar" let-header="header">
        {{ header.hours }}:{{ header.minutes === 0 ? '00' : header.minutes }}
      </ng-template>
    </daypilot-calendar>
  `
})
export class CalendarTemplatesComponent {
  config: DayPilot.CalendarConfig = {
    startDate: '2026-10-05',
    viewType: 'Week'
  };

  events: DayPilot.EventData[] = [
    {id: 1, text: 'Planning',
      start: '2026-10-05T09:00:00', end: '2026-10-05T10:30:00'}
  ];
}

The example uses all four supported templates. Keep only the templates you need. Calendar time headers expose hours and minutes; they do not use the Scheduler time-header context with date objects and a level.

Supported Templates and Context

Each entry lists a supported daypilotTemplate name and its context bindings. The let- declarations bind named context values; an unqualified let-item would request an implicit value, which these templates do not provide.

  • event: let-event="event".

    The DayPilot.Event displayed in the event element.

  • cell: let-cell="cell".

    An object with start and end (DayPilot.Date), resource (resource ID), column (DayPilot.Column), and numeric x/y indices.

  • columnHeader: let-column="column".

    The DayPilot.Column for the column header.

  • timeHeader: let-header="header".

    An object with numeric hours/minutes, start (string), and time (DayPilot.Duration).

The optional daypilotTemplateFor="calendar" qualifier selects this component's context for Angular template type checking. It is useful when a name such as cell has different context fields in different components. If specified, it must match the enclosing DayPilot component. Enable Angular's strictTemplates option to check context members while building your application.

Rendering and Application State

Define at most one template for each supported name in a component. A template takes precedence over the corresponding DOM-add callback; omit the template to use that callback instead. Existing DOM-removal callbacks still run.

The wrapper creates and disposes the Angular views as DayPilot renders and removes their elements. Keep values that must survive scrolling, navigation, or redraws in application state, rather than only in a rendered child component.

Availability

Availability of this feature in DayPilot editions:

ProductLitePro
DayPilot for JavaScript
DayPilot for ASP.NET WebForms
DayPilot for ASP.NET MVC
DayPilot for Java