The Angular monthly calendar displays events in a familiar month grid. It works well for leave planning, reservations, reminders, and milestones, including events that span several days.
The component is available in DayPilot Lite (open-source, Apache License 2.0) and DayPilot Pro (commercial). Both include Angular integration and TypeScript declarations.

Angular Monthly Calendar Features
A complete month at a glance. Show daily cells with appointments, reminders, and events spanning multiple days. Events that cross a week boundary continue on the following row.
Interactive scheduling. Let users select days to create an event, move events to another date, and resize their duration. Your application chooses the editor and saves the result.
Custom appearance. Set event colors, customize cell appearance, and use a context menu for application actions. Locales and the first-day-of-week setting adapt the display to your users.
Connected views. Share event data with the day/week Calendar and use the Navigator date picker to change the displayed month.
Additional Pro Options
Pro adds advanced scheduling and export options, including image export and Excel export. Choose the edition according to the required interactions and output formats; the core monthly view and ordinary event editing are available in both.
See the feature matrix for a detailed edition comparison.
Demos and Tutorials
Each tutorial includes a downloadable project. The edition used by the example is shown beside its link.
Calendar Views
Angular Calendar: Day/Week/Month Views (Open-Source) · Live demo (Lite)
Combine daily, weekly, and monthly views with a date picker and shared data.
Older Angular Projects
Angular 5 Monthly Calendar Quick Start Project (Pro)
Historical Angular 5 starter; current integration is shown below.Angular 4 Monthly Event Calendar Quick Start Project (Pro)
Historical Angular 4 starter; use it as a migration reference, not a new-project template.
Configure a Starter Project
Use Month UI Builder to explore settings in a live preview and download an Angular starter. Select the edition that matches your application. Continue adjusting the generated configuration in your own code.
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 Monthly Calendar
This calendar shows a three-day conference in October.
month.component.ts
import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';
@Component({
selector: 'app-month',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-month
[config]="config"
[events]="events"></daypilot-month>
`
})
export class MonthComponent {
config: DayPilot.MonthConfig = {
startDate: '2026-10-01',
weekStarts: 1
};
events: DayPilot.EventData[] = [
{id: 'conference', text: 'Conference', start: '2026-10-05', end: '2026-10-08'}
];
}
startDate selects the month; weekStarts: 1 starts each row on Monday. The conference occupies October 5–7: its October 8 end is exclusive. The grid also displays dates from adjacent months to fill its first and last weeks.
Import MonthComponent in the parent component and use <app-month></app-month> 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.
Load the Full Visible Month
Navigation changes the month before reading visibleStart() and visibleEnd(). These methods include the adjacent-month days in the grid. Request events that overlap this entire range, rather than only events inside the named month.
month-loading.component.ts
import {
Component, ChangeDetectorRef, inject, AfterViewInit, ViewChild
} from '@angular/core';
import {
DayPilot, DayPilotModule, DayPilotMonthComponent
} from '@daypilot/daypilot-lite-angular';
@Component({
selector: 'app-month',
standalone: true,
imports: [DayPilotModule],
template: `
<button (click)="navigate(-1)">Previous month</button>
<button (click)="navigate(1)">Next month</button>
<daypilot-month
#month
[config]="config"
[events]="events"></daypilot-month>
`
})
export class MonthComponent implements AfterViewInit {
@ViewChild('month') month!: DayPilotMonthComponent;
config: DayPilot.MonthConfig = {
startDate: '2026-10-01',
weekStarts: 1
};
events: DayPilot.EventData[] = [];
private changes = inject(ChangeDetectorRef);
private loadRequest = 0;
ngAfterViewInit() {
this.loadData();
}
navigate(offset: number) {
const start = new DayPilot.Date(this.config.startDate!).addMonths(offset);
this.config = {...this.config, startDate: start};
this.changes.detectChanges();
this.loadData();
}
async loadData() {
const request = ++this.loadRequest;
const start = this.month.control.visibleStart();
const end = this.month.control.visibleEnd();
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.
detectChanges() applies the new configuration before the range is read. After the asynchronous response, markForCheck() lets Angular display the new event array, including in zoneless applications.
Create Events by Selecting Time
This complete variation of the first example handles time range selection. The selection supplies the dates; the dialog supplies the name.
month-creation.component.ts
import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';
@Component({
selector: 'app-month',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-month
[config]="config"
[events]="events"></daypilot-month>
`
})
export class MonthComponent {
config: DayPilot.MonthConfig = {
startDate: '2026-10-01',
weekStarts: 1,
onTimeRangeSelected: async args => {
const modal = await DayPilot.Modal.prompt('Event name:', 'New event');
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: 'conference', text: 'Conference', start: '2026-10-05', end: '2026-10-08'}
];
}
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.
month-saving.component.ts
import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from '@daypilot/daypilot-lite-angular';
@Component({
selector: 'app-month',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-month
[config]="config"
[events]="events"></daypilot-month>
`
})
export class MonthComponent {
config: DayPilot.MonthConfig = {
startDate: '2026-10-01',
weekStarts: 1,
onEventMoved: args => this.saveEvent(args.e.data),
onEventResized: args => this.saveEvent(args.e.data)
};
events: DayPilot.EventData[] = [
{id: 'conference', text: 'Conference', start: '2026-10-05', end: '2026-10-08'}
];
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 Month API
Use the event collection API to find and rename the conference. The wrapper reference, button and handler are shown together.
month-api.component.ts
import {Component, ViewChild} from '@angular/core';
import {
DayPilot, DayPilotModule, DayPilotMonthComponent
} from '@daypilot/daypilot-lite-angular';
@Component({
selector: 'app-month',
standalone: true,
imports: [DayPilotModule],
template: `
<button (click)="renameEvent()">Rename conference</button>
<daypilot-month
#month
[config]="config"
[events]="events"></daypilot-month>
`
})
export class MonthComponent {
@ViewChild('month') month!: DayPilotMonthComponent;
config: DayPilot.MonthConfig = {
startDate: '2026-10-01',
weekStarts: 1
};
events: DayPilot.EventData[] = [
{id: 'conference', text: 'Conference', start: '2026-10-05', end: '2026-10-08'}
];
async renameEvent() {
const control = this.month.control;
const event = control.events.find('conference');
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.Month 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.
month-signal-loading.component.ts
import {
Component, ChangeDetectorRef, inject, AfterViewInit, ViewChild, signal
} from '@angular/core';
import {
DayPilot, DayPilotModule, DayPilotMonthComponent
} from '@daypilot/daypilot-lite-angular';
@Component({
selector: 'app-month',
standalone: true,
imports: [DayPilotModule],
template: `
<button (click)="navigate(-1)">Previous month</button>
<button (click)="navigate(1)">Next month</button>
<daypilot-month
#month
[config]="config"
[events]="events"></daypilot-month>
`
})
export class MonthComponent implements AfterViewInit {
@ViewChild('month') month!: DayPilotMonthComponent;
config: DayPilot.MonthConfig = {
startDate: '2026-10-01',
weekStarts: 1
};
events = signal<DayPilot.EventData[]>([]);
private changes = inject(ChangeDetectorRef);
private loadRequest = 0;
ngAfterViewInit() {
this.loadData();
}
navigate(offset: number) {
const start = new DayPilot.Date(this.config.startDate!).addMonths(offset);
this.config = {...this.config, startDate: start};
this.changes.detectChanges();
this.loadData();
}
async loadData() {
const request = ++this.loadRequest;
const start = this.month.control.visibleStart();
const end = this.month.control.visibleEnd();
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.
Availability
Availability of this feature in DayPilot editions:
| Product | Lite | Pro |
|---|---|---|
| DayPilot for JavaScript | ||
| DayPilot for ASP.NET WebForms | ||
| DayPilot for ASP.NET MVC | ||
| DayPilot for Java |
DayPilot