Gantt Critical Path
The critical path is the sequence of tasks with zero total slack — any delay to these tasks directly delays the project finish date. The Gantt plugin computes the critical path automatically from your dependency graph and highlights it visually.
Source code
---import GanttCriticalPath from './GanttCriticalPath.vue';---
<GanttCriticalPath client:only="vue" />import { defineCustomElements } from '@revolist/revogrid/loader';defineCustomElements();
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
const ganttConfig = { id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', zoomPreset: 'week' as const, visuals: { showCriticalPath: true, },};
const calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8, },];
const tasks: TaskEntity[] = [ { id: 't1', projectId: PROJECT_ID, parentId: null, wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't2', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't3', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'], }, { id: 't4', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't5', projectId: PROJECT_ID, parentId: null, wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [], }, { // On the critical path: Frontend → Launch (shorter chain) id: 't6', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { // NOT on the critical path: Backend finishes after Frontend, so it drives the end date id: 't7', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't8', projectId: PROJECT_ID, parentId: null, wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, 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'), createDefaultTaskTableColumn('startDate'), createDefaultTaskTableColumn('endDate'), createDefaultTaskTableColumn('duration'), createDefaultTaskTableColumn('percentDone'), ];
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/revogrid-enterprise';import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';import { currentThemeVue } from '../composables/useRandomData';
const { isDark } = currentThemeVue();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
const plugins = ref([GanttPlugin]);
const ganttConfig = ref({ id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', zoomPreset: 'week' as const, visuals: { showCriticalPath: true, },});
const calendars = ref<CalendarEntity[]>([ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8 },]);
const tasks = ref<TaskEntity[]>([ { id: 't1', projectId: PROJECT_ID, parentId: null, wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't2', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't3', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'], }, { id: 't4', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't5', projectId: PROJECT_ID, parentId: null, wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [], }, { id: 't6', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't7', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't8', projectId: PROJECT_ID, parentId: null, wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, 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'), createDefaultTaskTableColumn('startDate'), createDefaultTaskTableColumn('endDate'), createDefaultTaskTableColumn('duration'), createDefaultTaskTableColumn('percentDone'),]);</script>import React, { useMemo } from 'react';import { RevoGrid } from '@revolist/react-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
const tasks: TaskEntity[] = [ { id: 't1', projectId: PROJECT_ID, parentId: null, wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't2', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't3', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'], }, { id: 't4', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't5', projectId: PROJECT_ID, parentId: null, wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [], }, { id: 't6', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't7', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't8', projectId: PROJECT_ID, parentId: null, wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, 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: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8 },];
function GanttCriticalPath() { const ganttConfig = useMemo(() => ({ id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', zoomPreset: 'week' as const, visuals: { showCriticalPath: true }, }), []);
const columns = useMemo(() => [ createDefaultTaskTableColumn('wbs'), createDefaultTaskTableColumn('name'), createDefaultTaskTableColumn('startDate'), createDefaultTaskTableColumn('endDate'), createDefaultTaskTableColumn('duration'), createDefaultTaskTableColumn('percentDone'), ], []);
return ( <RevoGrid style={{ height: '500px' }} theme={isDark() ? 'darkCompact' : 'compact'} hideAttribution plugins={[GanttPlugin]} source={tasks} columns={columns} gantt={ganttConfig} ganttDependencies={dependencies} ganttCalendars={calendars} /> );}
export default GanttCriticalPath;import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';import { RevoGrid } from '@revolist/angular-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';import { currentTheme } from '../composables/useRandomData';
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
@Component({ selector: 'gantt-critical-path', standalone: true, imports: [RevoGrid], schemas: [NO_ERRORS_SCHEMA], template: ` <revo-grid style="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 GanttCriticalPathComponent { theme = currentTheme().isDark() ? 'darkCompact' : 'compact'; plugins = [GanttPlugin];
ganttConfig = { id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', zoomPreset: 'week' as const, visuals: { showCriticalPath: true }, };
calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8 }, ];
tasks: TaskEntity[] = [ { id: 't1', projectId: PROJECT_ID, parentId: null, wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't2', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't3', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0, progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'], }, { id: 't4', projectId: PROJECT_ID, parentId: 't1', wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't5', projectId: PROJECT_ID, parentId: null, wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [], }, { id: 't6', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't7', projectId: PROJECT_ID, parentId: 't5', wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [], }, { id: 't8', projectId: PROJECT_ID, parentId: null, wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0, progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, 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'), createDefaultTaskTableColumn('startDate'), createDefaultTaskTableColumn('endDate'), createDefaultTaskTableColumn('duration'), createDefaultTaskTableColumn('percentDone'), ];}Enabling Critical Path
Section titled “Enabling Critical Path”Set showCriticalPath: true in the visuals section of your project config:
grid.gantt = { // …required fields visuals: { showCriticalPath: true, },};Critical tasks and the dependency arrows connecting them are immediately highlighted in a distinct colour (red by default, customisable via CSS).
How It Works
Section titled “How It Works”The scheduler runs a forward pass followed by a backward pass over the dependency graph to compute:
- Early Start / Early Finish — the earliest each task can begin and end
- Late Start / Late Finish — the latest each task can begin and end without delaying the project
- Total Slack = Late Start − Early Start
A task is critical when its total slack equals zero. The critical path runs from the first task in the project to the last with no slack.
Dependency Types and the Critical Path
Section titled “Dependency Types and the Critical Path”All four dependency types participate in critical path analysis:
| Type | Effect |
|---|---|
finish-to-start | Successor cannot start until predecessor finishes — most common on critical paths |
start-to-start | Successor cannot start until predecessor starts |
finish-to-finish | Successor cannot finish until predecessor finishes |
start-to-finish | Less common; successor cannot finish until predecessor starts |
Lags (lagDays) are factored into the calculation. A positive lag adds slack; a negative lag reduces it.
Marking Tasks Manually
Section titled “Marking Tasks Manually”The isCritical field on a TaskEntity can pre-mark tasks for display before the scheduler runs (e.g. when loading persisted data):
grid.source = [ { id: 't6', name: 'Frontend Development', isCritical: true, // pre-marked; scheduler may override this // …other fields },];The scheduler will overwrite isCritical on each render cycle based on its own computation.
CSS Customisation
Section titled “CSS Customisation”Critical path styling uses data attributes on bar and arrow elements:
/* Critical task bar */.gantt-bar[data-critical] { --gantt-bar-color: #e53e3e;}
/* Critical dependency arrow */.gantt-dependency[data-critical] { stroke: #e53e3e;}