Skip to content

Gantt Baselines

A baseline is a saved snapshot of task dates and progress at a specific point in time (e.g. when the project was approved). The Gantt chart can overlay these baseline bars beneath the live bars, making schedule drift immediately visible.

Source code
Astro astro
---
import GanttBaseline from '@revolist/revogrid-examples/components/gantt/GanttBaseline.vue';
---

<GanttBaseline client:only="vue" />
TypeScript ts
// src/components/gantt/GanttBaseline.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();

import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity, BaselineSnapshot } 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: {
    showBaseline: true,
    baselineId: 'baseline-approved',
  },
};

const baselineColumnProps = [
  'wbs',
  'name',
  'startDate',
  'endDate',
  'startVarianceDays',
  'finishVarianceDays',
  'durationVarianceDays',
  'progressVariancePercent',
] as const;

const calendars: CalendarEntity[] = [
  {
    id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC',
    workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8,
  },
];

// Current (live) tasks — note Design slipped by 3 days vs baseline
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-27', durationDays: 18,
    progressPercent: 50, 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-27', durationDays: 13, // slipped from 10 → 13
    progressPercent: 30, 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-28', endDate: '2026-05-21', 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-28', endDate: '2026-05-14', 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-28', endDate: '2026-05-21', durationDays: 18,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't8', projectId: PROJECT_ID, parentId: null,
    wbsCode: '3', name: 'Launch', type: 'milestone',
    status: 'not-started',
    startDate: '2026-05-21', endDate: '2026-05-21', 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 },
];

// Baseline — the original approved plan before Visual Design slipped
const baselines: BaselineSnapshot[] = [
  {
    id: 'baseline-approved',
    name: 'Approved Plan',
    capturedAt: '2026-04-01T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 0 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 0 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 0 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 0 },
      { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0,  progressPercent: 0 },
    ],
  },
  {
    id: 'baseline-replan',
    name: 'Replan After Design Slip',
    capturedAt: '2026-04-15T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', durationDays: 18, progressPercent: 25 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 100 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 100 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', durationDays: 13, progressPercent: 20 },
      { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', durationDays: 0,  progressPercent: 0 },
    ],
  },
];

export function load(parentSelector: string) {
  const container = document.createElement('div');
  container.className = 'gantt-example-container';

  const toolbar = document.createElement('div');
  toolbar.className = 'gantt-toolbar';
  Object.assign(toolbar.style, {
    marginBottom: '1rem',
    display: 'flex',
    gap: '1rem',
    alignItems: 'center',
  });

  const label = document.createElement('label');
  Object.assign(label.style, {
    display: 'flex',
    alignItems: 'center',
    gap: '0.5rem',
    cursor: 'pointer',
  });

  const checkbox = document.createElement('input');
  checkbox.type = 'checkbox';
  checkbox.checked = ganttConfig.visuals.showBaseline;

  label.appendChild(checkbox);
  label.appendChild(document.createTextNode('Show Baseline'));
  toolbar.appendChild(label);

  const selectLabel = document.createElement('label');
  Object.assign(selectLabel.style, {
    display: 'flex',
    alignItems: 'center',
    gap: '0.5rem',
  });
  const select = document.createElement('select');
  for (const baseline of baselines) {
    const option = document.createElement('option');
    option.value = baseline.id;
    option.textContent = baseline.name;
    select.appendChild(option);
  }
  select.value = ganttConfig.visuals.baselineId;
  selectLabel.appendChild(document.createTextNode('Baseline'));
  selectLabel.appendChild(select);
  toolbar.appendChild(selectLabel);
  container.appendChild(toolbar);

  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.ganttBaselines = baselines;
  grid.source = tasks;
  grid.columns = baselineColumnProps.map((prop) => createDefaultTaskTableColumn(prop));

  container.appendChild(grid);
  document.querySelector(parentSelector)?.appendChild(container);

  checkbox.addEventListener('change', (e) => {
    const showBaseline = (e.target as HTMLInputElement).checked;
    grid.gantt = {
      ...grid.gantt,
      visuals: {
        ...grid.gantt.visuals,
        showBaseline,
      },
    };
  });

  select.addEventListener('change', (e) => {
    grid.gantt = {
      ...grid.gantt,
      visuals: {
        ...grid.gantt.visuals,
        baselineId: (e.target as HTMLSelectElement).value,
      },
    };
  });
}
Vue vue
<template>
  <div class="gantt-example-container">
    <div class="gantt-toolbar" :style="{ marginBottom: '1rem', display: 'flex', gap: '1rem', alignItems: 'center' }">
      <label :style="{ display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer' }">
        <input
          type="checkbox"
          v-model="showBaseline"
        />
        Show Baseline
      </label>
      <label :style="{ display: 'flex', alignItems: 'center', gap: '0.5rem' }">
        Baseline
        <select v-model="baselineId">
          <option v-for="baseline in baselines" :key="baseline.id" :value="baseline.id">
            {{ baseline.name }}
          </option>
        </select>
      </label>
    </div>
    <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"
      :gantt-baselines.prop="baselines"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity, BaselineSnapshot } 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 showBaseline = ref(true);
const baselineId = ref('baseline-approved');

const ganttConfig = computed(() => ({
  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: {
    showBaseline: showBaseline.value,
    baselineId: baselineId.value,
  },
}));

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-27', durationDays: 18,
    progressPercent: 50, 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-27', durationDays: 13,
    progressPercent: 30, 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-28', endDate: '2026-05-21', 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-28', endDate: '2026-05-14', 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-28', endDate: '2026-05-21', durationDays: 18,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't8', projectId: PROJECT_ID, parentId: null,
    wbsCode: '3', name: 'Launch', type: 'milestone',
    status: 'not-started',
    startDate: '2026-05-21', endDate: '2026-05-21', 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 baselines = ref<BaselineSnapshot[]>([
  {
    id: 'baseline-approved',
    name: 'Approved Plan',
    capturedAt: '2026-04-01T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 0 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 0 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 0 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 0 },
      { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0,  progressPercent: 0 },
    ],
  },
  {
    id: 'baseline-replan',
    name: 'Replan After Design Slip',
    capturedAt: '2026-04-15T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', durationDays: 18, progressPercent: 25 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 100 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 100 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', durationDays: 13, progressPercent: 20 },
      { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', durationDays: 0,  progressPercent: 0 },
    ],
  },
]);

const baselineColumnProps = [
  'wbs',
  'name',
  'startDate',
  'endDate',
  'startVarianceDays',
  'finishVarianceDays',
  'durationVarianceDays',
  'progressVariancePercent',
] as const;

const columns = ref(baselineColumnProps.map((prop) => createDefaultTaskTableColumn(prop)));
</script>
React tsx
// src/components/gantt/GanttBaseline.tsx
import React, { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity, BaselineSnapshot } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';

const { isDark } = currentTheme();

const PROJECT_ID = 'project-web-redesign';
const CALENDAR_ID = 'cal-standard';
const baselineColumnProps = [
  'wbs',
  'name',
  'startDate',
  'endDate',
  'startVarianceDays',
  'finishVarianceDays',
  'durationVarianceDays',
  'progressVariancePercent',
] as const;

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-27', durationDays: 18,
    progressPercent: 50, 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-27', durationDays: 13, // slipped
    progressPercent: 30, 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-28', endDate: '2026-05-21', 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-28', endDate: '2026-05-14', 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-28', endDate: '2026-05-21', durationDays: 18,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't8', projectId: PROJECT_ID, parentId: null,
    wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
    startDate: '2026-05-21', endDate: '2026-05-21', 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 },
];

const baselines: BaselineSnapshot[] = [
  {
    id: 'baseline-approved',
    name: 'Approved Plan',
    capturedAt: '2026-04-01T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 0 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 0 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 0 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 0 },
      { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0,  progressPercent: 0 },
    ],
  },
  {
    id: 'baseline-replan',
    name: 'Replan After Design Slip',
    capturedAt: '2026-04-15T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', durationDays: 18, progressPercent: 25 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 100 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 100 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', durationDays: 13, progressPercent: 20 },
      { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', durationDays: 0,  progressPercent: 0 },
    ],
  },
];

function GanttBaseline() {
  const [showBaseline, setShowBaseline] = React.useState(true);
  const [baselineId, setBaselineId] = React.useState('baseline-approved');
  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: { showBaseline, baselineId },
  }), [baselineId, showBaseline]);

  const columns = useMemo(() => baselineColumnProps.map((prop) => createDefaultTaskTableColumn(prop)), []);

  return (
    <div className="gantt-example-container">
      <div className="gantt-toolbar" style={{ marginBottom: '1rem', display: 'flex', gap: '1rem', alignItems: 'center' }}>
        <label style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer' }}>
          <input
            type="checkbox"
            checked={showBaseline}
            onChange={(e) => setShowBaseline(e.target.checked)}
          />
          Show Baseline
        </label>
        <label style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
          Baseline
          <select value={baselineId} onChange={(event) => setBaselineId(event.target.value)}>
            {baselines.map((baseline) => (
              <option key={baseline.id} value={baseline.id}>{baseline.name}</option>
            ))}
          </select>
        </label>
      </div>
      <RevoGrid
        style={{ height: '500px' }}
        theme={isDark() ? 'darkCompact' : 'compact'}
        hideAttribution
        plugins={[GanttPlugin]}
        source={tasks}
        columns={columns}
        gantt={ganttConfig}
        ganttDependencies={dependencies}
        ganttCalendars={calendars}
        ganttBaselines={baselines}
      />
    </div>
  );
}

export default GanttBaseline;
Angular ts
// src/components/gantt/GanttBaselineAngular.ts
import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RevoGrid } from '@revolist/angular-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity, BaselineSnapshot } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';

const PROJECT_ID = 'project-web-redesign';
const CALENDAR_ID = 'cal-standard';

@Component({
  selector: 'gantt-baseline-grid',
  standalone: true,
  // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
  schemas: [NO_ERRORS_SCHEMA],
  imports: [CommonModule, RevoGrid],
  template: `
    <div class="gantt-example-container">
      <div class="gantt-toolbar" style="margin-bottom: 1rem; display: flex; gap: 1rem; align-items: center">
        <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer">
          <input
            type="checkbox"
            [checked]="showBaseline"
            (change)="toggleBaseline($event)"
          />
          Show Baseline
        </label>
        <label style="display: flex; align-items: center; gap: 0.5rem">
          Baseline
          <select [value]="baselineId" (change)="selectBaseline($event)">
            <option *ngFor="let baseline of baselines" [value]="baseline.id">{{ baseline.name }}</option>
          </select>
        </label>
      </div>
      <revo-grid
        style="height: 500px"
        [theme]="theme"
        [hideAttribution]="true"
        [plugins]="plugins"
        [source]="tasks"
        [columns]="columns"
        [gantt]="ganttConfig"
        [ganttDependencies]="dependencies"
        [ganttCalendars]="calendars"
        [ganttBaselines]="baselines"
      ></revo-grid>
    </div>
  `,
  encapsulation: ViewEncapsulation.None,
})
export class GanttBaselineGridComponent {
  theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
  plugins = [GanttPlugin];
  showBaseline = true;
  baselineId = 'baseline-approved';
  ganttConfig = this.createGanttConfig();

  toggleBaseline(event: Event) {
    this.showBaseline = (event.target as HTMLInputElement).checked;
    this.updateGanttConfig();
  }

  selectBaseline(event: Event) {
    this.baselineId = (event.target as HTMLSelectElement).value;
    this.updateGanttConfig();
  }

  private createGanttConfig() {
    return {
      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: { showBaseline: this.showBaseline, baselineId: this.baselineId },
    };
  }

  private updateGanttConfig() {
    this.ganttConfig = this.createGanttConfig();
  }

  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-27', durationDays: 18,
      progressPercent: 50, 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-27', durationDays: 13,
      progressPercent: 30, 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-28', endDate: '2026-05-21', 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-28', endDate: '2026-05-14', 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-28', endDate: '2026-05-21', durationDays: 18,
      progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
    },
    {
      id: 't8', projectId: PROJECT_ID, parentId: null,
      wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
      startDate: '2026-05-21', endDate: '2026-05-21', 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 },
  ];

  baselines: BaselineSnapshot[] = [
    {
      id: 'baseline-approved',
      name: 'Approved Plan',
      capturedAt: '2026-04-01T08:00:00Z',
      tasks: [
        { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 0 },
        { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 0 },
        { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 0 },
        { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 0 },
        { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
        { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0 },
        { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
        { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0,  progressPercent: 0 },
      ],
    },
    {
      id: 'baseline-replan',
      name: 'Replan After Design Slip',
      capturedAt: '2026-04-15T08:00:00Z',
      tasks: [
        { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', durationDays: 18, progressPercent: 25 },
        { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 100 },
        { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 100 },
        { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', durationDays: 13, progressPercent: 20 },
        { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
        { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', durationDays: 13, progressPercent: 0 },
        { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', durationDays: 18, progressPercent: 0 },
        { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', durationDays: 0,  progressPercent: 0 },
      ],
    },
  ];

  columns = [
    'wbs',
    'name',
    'startDate',
    'endDate',
    'startVarianceDays',
    'finishVarianceDays',
    'durationVarianceDays',
    'progressVariancePercent',
  ].map((prop) => createDefaultTaskTableColumn(prop as any));
}

Pass one or more BaselineSnapshot objects via grid.ganttBaselines:

grid.ganttBaselines = [
{
id: 'baseline-approved',
name: 'Approved Plan',
capturedAt: '2026-04-01T08:00:00Z',
tasks: [
{ taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-22', durationDays: 13, progressPercent: 0 },
{ taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5, progressPercent: 0 },
{ taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0, progressPercent: 0 },
{ taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-22', durationDays: 8, progressPercent: 0 },
{ taskId: 't5', startDate: '2026-04-23', endDate: '2026-05-16', durationDays: 18, progressPercent: 0 },
{ taskId: 't6', startDate: '2026-04-23', endDate: '2026-05-09', durationDays: 13, progressPercent: 0 },
{ taskId: 't7', startDate: '2026-04-23', endDate: '2026-05-16', durationDays: 18, progressPercent: 0 },
{ taskId: 't8', startDate: '2026-05-16', endDate: '2026-05-16', durationDays: 0, progressPercent: 0 },
],
},
];

You can also capture a snapshot from the current scheduled state:

const plugins = await grid.getPlugins();
const gantt = plugins.find((plugin) => plugin.constructor?.name === 'GanttPlugin');
const baseline = gantt?.captureBaseline?.({
id: 'baseline-current',
name: 'Current Approved Plan',
capturedAt: '2026-04-15T08:00:00Z',
});
if (baseline) {
grid.ganttBaselines = [
...(grid.ganttBaselines ?? []),
baseline,
];
}

Turn on baseline rendering through the visuals key in your project config:

grid.gantt = {
// …required fields
visuals: {
showBaseline: true,
baselineId: 'baseline-approved', // optional — defaults to the latest snapshot
},
};

When showBaseline is true, a translucent bar is drawn behind each live task bar showing its baseline position.

You can store several snapshots and switch between them at runtime:

// Initially show the approved plan
grid.gantt = { ...config, visuals: { showBaseline: true, baselineId: 'baseline-approved' } };
// Switch to a re-baseline after scope change
grid.gantt = { ...config, visuals: { showBaseline: true, baselineId: 'baseline-replan' } };

When a baseline is visible, each projected task row also exposes optional variance fields:

FieldDescription
startVarianceDaysCurrent scheduled start minus baseline start, in calendar days
finishVarianceDaysCurrent scheduled finish minus baseline finish, in calendar days
durationVarianceDaysCurrent scheduled duration minus baseline duration
progressVariancePercentCurrent progress minus baseline progress, in percentage points

Add the default columns when users need to inspect drift numerically:

grid.columns = [
createDefaultTaskTableColumn('name'),
createDefaultTaskTableColumn('startVarianceDays'),
createDefaultTaskTableColumn('finishVarianceDays'),
createDefaultTaskTableColumn('durationVarianceDays'),
createDefaultTaskTableColumn('progressVariancePercent'),
];
FieldTypeDescription
idBaselineIdUnique identifier for this snapshot
namestringHuman-readable label (e.g. "Q1 Approved Plan")
capturedAtISODateTimeStringWhen the snapshot was taken
tasksBaselineTaskSnapshot[]Per-task date and progress records
FieldTypeDescription
taskIdTaskIdReferences the live task
startDateISODateStringBaseline start date
endDateISODateStringBaseline end date
durationDaysnumberBaseline duration in calendar days
progressPercentnumberBaseline progress (0–100)