The Angular monthly calendar arranges dates into week rows, with one cell per day. Events can occupy one day or span several dates; an event crossing a week boundary continues on the next row. The first and last rows include dates from neighboring months.
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
DayPilot Lite and Pro
One-day and multi-day events. Each record supplies an ID, text, start, and end. Event ends are exclusive: the conference in the introductory example starts on October 5 and ends on October 8, so it occupies October 5–7. Month places the event in the appropriate cells and week rows.
Select, move, and resize. Select days to create an event, move it to another date, or resize its duration. The selection callback supplies dates to your editor; callbacks after moving or resizing can save the updated record.
Colors and event actions. Set event colors, customize day cells, and attach a context menu. Active areas add positioned icons or controls inside an event. The first-day-of-week setting and locale control the calendar's date layout and formatting.
Navigation and connected views. Change the displayed month using
startDate, or connect a Angular date picker. Share event data with the day/week Calendar. When loading events, use the full visible range, including adjacent-month days; the loading example below shows how to read it.
Additional DayPilot Pro Features
Image export. Create a JPEG, PNG, or SVG image of the calendar. The export guide explains the supported event styling and how to obtain the output.
Excel export. Export the full month grid to an Excel spreadsheet, including overlapping and multi-day events. Your application supplies an ExcelJS reference; the component maps the calendar dates and events into spreadsheet cells.
See the feature matrix for a detailed edition comparison.
Move from a Monthly Overview to a Selected Day

The illustration shows the weekly view of the same connected calendar.
The Angular combined-view example places Day, Week, and Month buttons beside a date picker. The monthly view uses <daypilot-month>; the day and week views use separate <daypilot-calendar> instances. All three bind to the same loaded event collection, while each has its own configuration. Try switching views (Lite).
Select a date in the date picker, open Month to see its surrounding weeks, then switch to Day. The application keeps the selected day and updates each component's startDate. The date picker's selectMode follows the active view, so its highlight changes between a day, week, and month. Supplying the events to the date picker also marks busy dates in bold.
Separate configurations let the sample use compact event bars in Month and larger event boxes in the hourly views. The shared collection supplies the records; the buttons and date-change handler coordinate which view and date are shown.
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 an 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.
Customize Content with Angular Templates (Pro)
Use Angular markup for Month events and day cells. For example, render an event title in bold and show the number of events associated with each day.
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-month>. 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-month-templates',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-month [config]="config" [events]="events">
<ng-template daypilotTemplate="event"
daypilotTemplateFor="month" let-event="event">
<strong>{{ event.text() }}</strong>
</ng-template>
<ng-template daypilotTemplate="cell"
daypilotTemplateFor="month" let-cell="cell">
<small>{{ cell.events().length }} events</small>
</ng-template>
</daypilot-month>
`
})
export class MonthTemplatesComponent {
config: DayPilot.MonthConfig = {
startDate: '2026-10-01'
};
events: DayPilot.EventData[] = [
{id: 1, text: 'Planning',
start: '2026-10-05', end: '2026-10-07'}
];
}
The cell template adds content to the day cell; it does not replace the event template. cell.events() is a method, unlike the Navigator template context, which uses cell.events.all().
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
startand exclusiveend(DayPilot.Date). Callcell.events()to get the DayPilot.Event objects associated with the cell.
The optional daypilotTemplateFor="month" 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:
| Product | Lite | Pro |
|---|---|---|
| DayPilot for JavaScript | ||
| DayPilot for ASP.NET WebForms | ||
| DayPilot for ASP.NET MVC | ||
| DayPilot for Java |
DayPilot