Overview Scheduling
The Gantt scheduler computes effective task dates from authored dates, duration, task mode, dependencies, lag/lead, calendars, constraints, deadlines, resources, actuals, split ranges, and optional resource leveling.
Its compatibility target is Microsoft Project scheduling behavior: automatic tasks are dependency-safe, manual tasks preserve authored dates but show warnings, deadlines warn without constraining, and leveling can delay eligible work.
Source code
---import '@revolist/gantt/styles.css';import GanttScheduling from '@revolist/revogrid-examples/components/gantt/GanttScheduling.vue';---
<GanttScheduling client:only="vue" />import { defineCustomElements } from '@revolist/revogrid/loader';defineCustomElements();
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity } from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-us';
// Calendar-aware scheduling: durations are in working days (Mon–Fri, excluding holidays)const ganttConfig = { id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'America/New_York', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'day-week' as const, scheduling: { excludeHolidaysFromDuration: true, // durations skip weekends and holidays }, visuals: { shadeNonWorkingTime: true, // shade weekend columns on the timeline projectLineDate: '2026-04-06', // vertical status-date line },};
// US calendar with public holidaysconst calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'US Standard', timeZone: 'America/New_York', workingDays: [1, 2, 3, 4, 5], // Mon–Fri holidays: [ '2026-05-25', // Memorial Day '2026-07-04', // Independence Day ], hoursPerDay: 8, },];
const tasks: GanttTaskSourceRow[] = [ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', duration: 15, percentDone: 60, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', duration: 10, percentDone: 40, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', // constraint: cannot start before May 4 (waiting on external API) startDate: '2026-05-04', endDate: '2026-05-20', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], constraintType: 'start-no-earlier-than', constraintDate: '2026-05-04', }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], deadlineDate: '2026-05-22', // deadline marker — project expects early delivery }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-28', endDate: '2026-05-28', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], },];
const dependencies: DependencyEntity[] = [ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, },];
export function load(parentSelector: string) { const grid = document.createElement('revo-grid');
grid.theme = isDark() ? 'darkCompact' : 'compact'; grid.hideAttribution = true; grid.plugins = [GanttPlugin]; grid.gantt = ganttConfig; grid.ganttCalendars = calendars; grid.ganttDependencies = dependencies; grid.source = tasks; grid.columns = [ createDefaultTaskTableColumn('wbs'), createDefaultTaskTableColumn('name'), ];
document.querySelector(parentSelector)?.appendChild(grid);}<template> <RevoGrid hide-attribution style="height: 500px" :theme="isDark ? 'darkCompact' : 'compact'" :plugins="plugins" :source="tasks" :columns="columns" :gantt.prop="ganttConfig" :gantt-dependencies.prop="dependencies" :gantt-calendars.prop="calendars" /></template>
<script setup lang="ts">import { ref } from 'vue';import RevoGrid from '@revolist/vue3-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity } from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentThemeVue } from '../composables/useRandomData';
const { isDark } = currentThemeVue();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-us';
const plugins = ref([GanttPlugin]);
const ganttConfig = ref({ id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'America/New_York', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'day-week' as const, scheduling: { excludeHolidaysFromDuration: true, }, visuals: { shadeNonWorkingTime: true, projectLineDate: '2026-04-06', },});
const calendars = ref<CalendarEntity[]>([ { id: CALENDAR_ID, name: 'US Standard', timeZone: 'America/New_York', workingDays: [1, 2, 3, 4, 5], holidays: ['2026-05-25', '2026-07-04'], hoursPerDay: 8, },]);
const tasks = ref<GanttTaskSourceRow[]>([ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', duration: 15, percentDone: 60, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', duration: 10, percentDone: 40, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-05-04', endDate: '2026-05-20', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], constraintType: 'start-no-earlier-than', constraintDate: '2026-05-04', }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], deadlineDate: '2026-05-22', }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-28', endDate: '2026-05-28', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], },]);
const dependencies = ref<DependencyEntity[]>([ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, },]);
const columns = ref([ createDefaultTaskTableColumn('wbs'), createDefaultTaskTableColumn('name'),]);</script>import React, { useMemo } from 'react';import { RevoGrid } from '@revolist/react-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity } from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-us';
const tasks: GanttTaskSourceRow[] = [ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', duration: 15, percentDone: 60, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', duration: 10, percentDone: 40, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-05-04', endDate: '2026-05-20', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], constraintType: 'start-no-earlier-than', constraintDate: '2026-05-04', }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], deadlineDate: '2026-05-22', }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-28', endDate: '2026-05-28', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], },];
const dependencies: DependencyEntity[] = [ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, },];
const calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'US Standard', timeZone: 'America/New_York', workingDays: [1, 2, 3, 4, 5], holidays: ['2026-05-25', '2026-07-04'], hoursPerDay: 8, },];
function GanttScheduling() { const ganttConfig = useMemo( () => ({ id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'America/New_York', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'day-week' as const, scheduling: { excludeHolidaysFromDuration: true, }, visuals: { shadeNonWorkingTime: true, projectLineDate: '2026-04-06', }, }), [], );
const columns = useMemo( () => [ createDefaultTaskTableColumn('wbs'), createDefaultTaskTableColumn('name'), ], [], );
return ( <RevoGrid style={{ height: '500px' }} theme={isDark() ? 'darkCompact' : 'compact'} hideAttribution plugins={[GanttPlugin]} source={tasks} columns={columns} gantt={ganttConfig} ganttDependencies={dependencies} ganttCalendars={calendars} /> );}
export default GanttScheduling;import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';import { RevoGrid } from '@revolist/angular-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity } from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentTheme } from '../composables/useRandomData';
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-us';
@Component({ selector: 'gantt-scheduling-grid', standalone: true, imports: [RevoGrid], // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs. schemas: [NO_ERRORS_SCHEMA], template: ` <revo-grid style="min-height: 500px" [theme]="theme" [hideAttribution]="true" [plugins]="plugins" [source]="tasks" [columns]="columns" [gantt]="ganttConfig" [ganttDependencies]="dependencies" [ganttCalendars]="calendars" ></revo-grid> `, encapsulation: ViewEncapsulation.None,})export class GanttSchedulingGridComponent { theme = currentTheme().isDark() ? 'darkCompact' : 'compact'; plugins = [GanttPlugin];
ganttConfig = { id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'America/New_York', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'day-week' as const, scheduling: { excludeHolidaysFromDuration: true, }, visuals: { shadeNonWorkingTime: true, projectLineDate: '2026-04-06', }, };
calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'US Standard', timeZone: 'America/New_York', workingDays: [1, 2, 3, 4, 5], holidays: ['2026-05-25', '2026-07-04'], hoursPerDay: 8, }, ];
tasks: GanttTaskSourceRow[] = [ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', duration: 15, percentDone: 60, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', duration: 10, percentDone: 40, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-05-04', endDate: '2026-05-20', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], constraintType: 'start-no-earlier-than', constraintDate: '2026-05-04', }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-27', endDate: '2026-05-28', duration: 24, percentDone: 0, calendarId: CALENDAR_ID, tags: [], deadlineDate: '2026-05-22', }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-28', endDate: '2026-05-28', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], }, ];
dependencies: DependencyEntity[] = [ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, ];
columns = [ createDefaultTaskTableColumn('wbs'), createDefaultTaskTableColumn('name'), ];}Scheduling Configuration
Section titled “Scheduling Configuration”Configure scheduling policies under grid.gantt.scheduling:
grid.gantt = { scheduling: { taskModeDefault: 'auto', scheduleFrom: 'project-start', projectStartDate: '2026-04-06', excludeHolidaysFromDuration: true, lagCalendar: 'working-days', manualDependencyViolationBehavior: 'warn', resourceLeveling: 'warn', effortModeDefault: 'fixed-duration', progressRescheduling: 'remaining-duration', },};Definition source: packages/gantt/src/gantt/grid/gantt-plugin.types.ts.
Scheduling Warnings
Section titled “Scheduling Warnings”Warnings are reported as scheduler conflicts and projected into rows:
| Code | Meaning |
|---|---|
manual-dependency-violation | A manual task starts before an active dependency allows. |
dependency-constraint-conflict | A dependency cannot be satisfied because an explicit constraint wins. |
hard-constraint-conflict | A must-start/must-finish constraint overrides dependencies. |
constraint-window-conflict | Soft constraint and dependency windows do not overlap. |
deadline-missed | A task finishes after deadlineDate. |
resource-overallocation | A resource exceeds capacity on a scheduled working date. |
resource-leveling-adjustment | Auto-leveling shifted a task to remove over-allocation. |
Performance
Section titled “Performance”Large-project scheduler performance is covered by the Gantt benchmark suite:
pnpm --filter @revolist/gantt benchThe benchmark exercises 1,000 and 3,000 task snapshots with dense dependencies and auto-leveling.
Next Steps
Section titled “Next Steps”Dive deeper into specific scheduling topics:
- MSP Compatibility: How RevoGrid maps to Microsoft Project.
- Engine Logic: The 5-step pipeline and conflict resolution.
- Scheduling Direction: Forward (ASAP) vs. Backward (ALAP).
- Calendars & Duration: Working days, holidays, and lag calendars.
- Dependencies: FS, SS, FF, SF and lag/lead.
- Task Modes: Manual vs. Automatic scheduling.
- Constraints: SNET, MSO, MFO and soft/hard rules.
- Deadlines: Target dates and missed deadline warnings.
- Resources & Assignments: Resource capacity and assignments.
- Resource Planning View: Resource-centric timeline view.
- Resource Leveling: Auto-leveling logic and priorities.
- Effort Modes: Fixed work, duration, and units.
- Actuals & Progress: Tracking real-world status.
- Split Tasks: Managing work gaps.
- Critical Path: Slack and schedule analysis.