Skip to content

Visual Configuration

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));
}

gantt.visuals controls overlays and rendering hooks:

  • showBaseline, baselineId
  • showCriticalPath
  • showTaskLabels
  • projectLineDate, showTodayLine, milestoneLines
  • timeRanges, shadeNonWorkingTime
  • taskMarkerHook, taskBarColorHook, taskBarContentHook
  • taskTooltipFields, taskTooltipHook

Use taskTooltipFields when you only need to choose which built-in fields appear in task-bar tooltips:

grid.gantt = {
...project,
visuals: {
taskTooltipFields: [
'name',
'startDate',
'endDate',
{ field: 'percentDone', label: 'Complete' },
'assignees',
],
},
};

taskTooltipFields is an ordered array. Each entry can be a field id string or an object with a field and optional label:

type GanttTaskTooltipField =
| GanttTaskTooltipFieldId
| { field: GanttTaskTooltipFieldId; label?: string };

Object entries let you rename a built-in line. Set label: '' to render only the value without a Label: prefix.

visuals: {
taskTooltipFields: [
{ field: 'name', label: '' },
{ field: 'percentDone', label: 'Done' },
],
}

Supported built-in fields:

FieldTooltip output
summaryTask name and completion percent, for example Design - 50%.
nameTask name.
percentDoneCompletion percent.
taskTypeHuman-readable task type.
statusHuman-readable task status.
startDateScheduled start date, formatted with gantt.dateFormats.tooltip.
endDateScheduled end date, formatted with gantt.dateFormats.tooltip.
durationDuration in days.
taskModeAuto Scheduled or Manually Scheduled.
schedulingWarningsScheduling warnings joined into one line; skipped when empty.
costFormatted task cost; skipped when empty.
assigneesComma-separated assignee names; skipped when empty.

When taskTooltipFields is omitted, Gantt keeps the default tooltip: summary, taskType, status, startDate, endDate, duration, taskMode, schedulingWarnings, cost, and assignees. An empty array intentionally renders an empty tooltip.

taskTooltipHook has priority over taskTooltipFields and can replace the whole tooltip string:

visuals: {
taskTooltipFields: ['name'],
taskTooltipHook: ({ row }) => `${row.name}\n${row.status}`,
}

Return null or undefined from taskTooltipHook to fall back to taskTooltipFields or the default tooltip. Use the hook for custom row metadata that is not part of the built-in field list.

Type source: packages/enterprise/plugins/gantt/grid/gantt-plugin.types.ts. Rendering sources: features/timeline/*, grid/gantt-column-type.ts.