The Angular Gantt chart displays a project schedule as task rows and a horizontal timeline. Show task hierarchies, milestones, dependencies, and progress, and let users adjust task dates directly.
This component is included in DayPilot Pro for JavaScript. It is not included in DayPilot Lite.

Angular Gantt Features
Task rows and groups. Each task has its own row and date range. Put related tasks in a
childrenarray to form a task hierarchy. A group bar spans its children, and expanding or collapsing the row switches between the group summary and individual tasks.Progress and milestones. Supply
completeto display a percentage and progress bar. A milestone marks one date; the introductory example ends with a release milestone after Planning and Implementation.Dependency endpoints. A link identifies two tasks and the endpoints it connects. A finish-to-start link runs from the predecessor's end to the successor's start; other link types connect their start or finish points differently. Your application supplies any rules for changing related task dates.
Editing on the timeline. Move a task to change its dates, or resize it to change its duration. The examples below use the automatic update behavior and then save the changed record in a callback.
Details beside the task bar. Row-header columns can display task fields or formatted values. Choose the timeline range and scale independently, and use image export to capture the chart.
Keep the Timeline Header Visible in a Full-Height Layout

The Angular layout example gives the chart a parent container with a defined height and lets you switch between two sizing modes. Parent100Pct fills that height even with a few rows. Max100Pct, shown here, grows with the task list until it reaches the parent height. Additional rows then scroll inside the chart while the time header stays visible. Compare the height modes.
The parent layout reserves space for the toolbar; heightSpec determines how the chart uses the remaining area. The sample updates an Angular configuration signal when you change the selector. This works with a chart embedded in an application page as well as a layout filling the browser window.
Save Task Edits and Hierarchy Changes
The Angular/PHP example connects separate editing actions to a JSON backend: moving or resizing saves task dates, and dragging a row saves its parent and order. The new-row editor sends a task name to the backend and adds the task using the returned database ID. A custom delete icon calls the sample's subtree-deletion endpoint, which also removes links to the deleted tasks.
These handlers show how the Gantt interactions connect to stored project data. The download includes an Angular frontend and a PHP backend with SQLite by default and a MySQL option; your application can use the same callbacks with a different service.
Demos and Tutorials
Each tutorial includes a downloadable project. The edition used by the example is shown beside its link.
Gantt Applications
Angular Gantt Chart Component (TypeScript + PHP/MySQL) (Pro)
Build a task hierarchy with a PHP JSON backend; the download includes SQLite/MySQL setup options.Angular Gantt Chart: Full Screen Layout · Live demo (Pro)
Compare a chart that fills its parent with one that grows to fit its rows, keeping room for the toolbar.
Older Angular Project
Angular 5 Gantt Chart Quick Start Project (Pro)
Historical Angular 5 Gantt starter; use the current example below for a new application.
Configure a Starter Project
Use Gantt UI Builder to explore settings in a live preview and download an Angular starter. Continue adjusting the generated configuration in your own code.
Installation
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 Project with Dependencies
This project has a planning task, an implementation task and a release milestone. The links show the order of the work.
gantt.component.ts
import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from 'daypilot-pro-angular';
@Component({
selector: 'app-gantt',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-gantt
[config]="config"
[tasks]="tasks"
[links]="links"></daypilot-gantt>
`
})
export class GanttComponent {
config: DayPilot.GanttConfig = {
startDate: '2026-10-01',
days: 31,
scale: 'Day',
timeHeaders: [{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]
};
tasks: DayPilot.TaskData[] = [
{id: 'planning', text: 'Planning', start: '2026-10-05', end: '2026-10-08'},
{id: 'implementation', text: 'Implementation', start: '2026-10-08', end: '2026-10-20'},
{id: 'release', text: 'Release', type: 'Milestone', start: '2026-10-20'}
];
links: DayPilot.LinkData[] = [
{id: 'L1', from: 'planning', to: 'implementation', type: 'FinishToStart'},
{id: 'L2', from: 'implementation', to: 'release', type: 'FinishToStart'}
];
}
A task has a unique id, display text, and start/end dates. Ends are exclusive: Planning occupies October 5–7. A milestone uses type: "Milestone" and a start date. Each link connects two task IDs; FinishToStart connects the predecessor’s finish to the successor’s start.
Import GanttComponent in the parent component and use <app-gantt></app-gantt> in its template.
See task loading for data formats and loading options.
Dependency links visualize relationships. The application decides how related tasks should be rescheduled and stores any link changes. Use task groups to organize a larger project into a hierarchy.
Load Tasks and Links Together
Load a project as {tasks: [...], links: [...]}. Assign both collections from the same response so that every dependency refers to a task in that project.
gantt-loading.component.ts
import {Component, ChangeDetectorRef, inject, OnInit} from '@angular/core';
import {DayPilot, DayPilotModule} from 'daypilot-pro-angular';
@Component({
selector: 'app-gantt',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-gantt
[config]="config"
[tasks]="tasks"
[links]="links"></daypilot-gantt>
`
})
export class GanttComponent implements OnInit {
config: DayPilot.GanttConfig = {
startDate: '2026-10-01',
days: 31,
scale: 'Day',
timeHeaders: [{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]
};
tasks: DayPilot.TaskData[] = [];
links: DayPilot.LinkData[] = [];
private changes = inject(ChangeDetectorRef);
private loadRequest = 0;
ngOnInit() {
this.loadData();
}
async loadData() {
const request = ++this.loadRequest;
const url = '/api/projects/1';
try {
const {data} = await DayPilot.Http.get(url);
if (request !== this.loadRequest) { return; }
this.tasks = data.tasks;
this.links = data.links;
this.changes.markForCheck();
} catch {
if (request === this.loadRequest) {
await DayPilot.Modal.alert('Could not load data.');
}
}
}
}
The /api/projects/1 URL represents your own backend. Failed requests display a DayPilot dialog.
Move, Resize and Save Tasks
Moving changes the task 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.
gantt-saving.component.ts
import {Component} from '@angular/core';
import {DayPilot, DayPilotModule} from 'daypilot-pro-angular';
@Component({
selector: 'app-gantt',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-gantt
[config]="config"
[tasks]="tasks"
[links]="links"></daypilot-gantt>
`
})
export class GanttComponent {
config: DayPilot.GanttConfig = {
startDate: '2026-10-01',
days: 31,
scale: 'Day',
timeHeaders: [{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}],
onTaskMoved: args => this.saveTask(args.task.data),
onTaskResized: args => this.saveTask(args.task.data)
};
tasks: DayPilot.TaskData[] = [
{id: 'planning', text: 'Planning', start: '2026-10-05', end: '2026-10-08'},
{id: 'implementation', text: 'Implementation', start: '2026-10-08', end: '2026-10-20'},
{id: 'release', text: 'Release', type: 'Milestone', start: '2026-10-20'}
];
links: DayPilot.LinkData[] = [
{id: 'L1', from: 'planning', to: 'implementation', type: 'FinishToStart'},
{id: 'L2', from: 'implementation', to: 'release', type: 'FinishToStart'}
];
async saveTask(data: DayPilot.TaskData) {
try {
await DayPilot.Http.put(`/api/tasks/${data.id}`, data);
} catch {
await DayPilot.Modal.alert('The change could not be saved.');
}
}
}
The /api/tasks/{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 taskMoveHandling or taskResizeHandling to "Disabled".
Handle a Task Click
To display the clicked item’s name, add this callback to config:
onTaskClick: args => DayPilot.Modal.alert(DayPilot.Util.escapeHtml(args.task.text()))
DayPilot.Modal.alert() accepts HTML. escapeHtml() displays the item’s name as plain text.
Access the Gantt API
Find the release milestone by ID and scroll the timeline to its start. This is useful when a booking or task lies outside the current horizontal viewport.
gantt-api.component.ts
import {Component, ViewChild} from '@angular/core';
import {DayPilot, DayPilotModule, DayPilotGanttComponent} from 'daypilot-pro-angular';
@Component({
selector: 'app-gantt',
standalone: true,
imports: [DayPilotModule],
template: `
<button (click)="showRelease()">Show release</button>
<daypilot-gantt
#gantt
[config]="config"
[tasks]="tasks"
[links]="links"></daypilot-gantt>
`
})
export class GanttComponent {
@ViewChild('gantt') gantt!: DayPilotGanttComponent;
config: DayPilot.GanttConfig = {
startDate: '2026-10-01',
days: 31,
scale: 'Day',
timeHeaders: [{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]
};
tasks: DayPilot.TaskData[] = [
{id: 'planning', text: 'Planning', start: '2026-10-05', end: '2026-10-08'},
{id: 'implementation', text: 'Implementation', start: '2026-10-08', end: '2026-10-20'},
{id: 'release', text: 'Release', type: 'Milestone', start: '2026-10-20'}
];
links: DayPilot.LinkData[] = [
{id: 'L1', from: 'planning', to: 'implementation', type: 'FinishToStart'},
{id: 'L2', from: 'implementation', to: 'release', type: 'FinishToStart'}
];
showRelease() {
const control = this.gantt.control;
const task = control.tasks.find('release');
control.scrollTo(task.start());
}
}
@ViewChild provides the wrapper; its control property exposes the underlying JavaScript component after initialization. The wrapper creates and disposes it. See the DayPilot.Gantt 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.
gantt-signal-loading.component.ts
import {Component, OnInit, signal} from '@angular/core';
import {DayPilot, DayPilotModule} from 'daypilot-pro-angular';
@Component({
selector: 'app-gantt',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-gantt
[config]="config"
[tasks]="tasks"
[links]="links"></daypilot-gantt>
`
})
export class GanttComponent implements OnInit {
config: DayPilot.GanttConfig = {
startDate: '2026-10-01',
days: 31,
scale: 'Day',
timeHeaders: [{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]
};
tasks = signal<DayPilot.TaskData[]>([]);
links = signal<DayPilot.LinkData[]>([]);
private loadRequest = 0;
ngOnInit() {
this.loadData();
}
async loadData() {
const request = ++this.loadRequest;
const url = '/api/projects/1';
try {
const {data} = await DayPilot.Http.get(url);
if (request !== this.loadRequest) { return; }
this.tasks.set(data.tasks);
this.links.set(data.links);
} catch {
if (request === this.loadRequest) {
await DayPilot.Modal.alert('Could not load data.');
}
}
}
}
Bind the signal itself with [tasks]="tasks". Binding its current value with () instead uses the ordinary input path. Keep one form consistently. Signals require Angular 16 or later.
Customize Content with Angular Templates (Pro)
Use Angular markup for Gantt task bars and row headers. Both templates receive the task, so you can display the same project data on the timeline and beside it.
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-gantt>. 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-gantt-templates',
standalone: true,
imports: [DayPilotModule],
template: `
<daypilot-gantt [config]="config" [tasks]="tasks">
<ng-template daypilotTemplate="task"
daypilotTemplateFor="gantt" let-task="task">
<strong>{{ task.text() }}</strong>
</ng-template>
<ng-template daypilotTemplate="rowHeader"
daypilotTemplateFor="gantt" let-task="task" let-x="x">
<span [attr.title]="'Column ' + x">{{ task.text() }}</span>
</ng-template>
</daypilot-gantt>
`
})
export class GanttTemplatesComponent {
config: DayPilot.GanttConfig = {
startDate: '2026-10-01',
days: 14,
scale: 'Day',
timeHeaders: [{groupBy: 'Day', format: 'd'}]
};
tasks: DayPilot.TaskData[] = [
{id: 'planning', text: 'Planning',
start: '2026-10-05', end: '2026-10-08'}
];
}
The rowHeader template receives task and x. Use x when the chart has multiple row-header columns. The Gantt template name for a task bar is task, even though Scheduler and Calendar use event for their event elements.
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.
task:let-task="task".The DayPilot.Task displayed on the timeline. Call
task.text()or readtask.data.rowHeader:let-task="task" let-x="x".The DayPilot.Task for the row and zero-based row-header column index
x. This context exposestask, not a Schedulerrow.
The optional daypilotTemplateFor="gantt" qualifier selects this component's context for Angular template type checking. It is useful when a name such as rowHeader 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