Skip to content

Gantt Quick Start — React

Source code
TypeScript ts
// src/components/gantt/GanttBasic.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();

import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars, dependencies, ganttConfig, initiallyHiddenColumnProps, tasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();
const columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));

export function load(parentSelector: string) {
  const parent = document.querySelector(parentSelector);
  if (!parent) {
    return () => {};
  }

  const root = document.createElement('section');
  const grid = document.createElement('revo-grid');

  root.className = 'gantt-basic-demo';
  grid.className = 'gantt-basic-grid';
  grid.theme = isDark() ? 'darkCompact' : 'compact';
  grid.hideAttribution = true;
  grid.canMoveColumns = true;
  grid.plugins = [GanttPlugin];
  grid.gantt = ganttConfig;
  grid.ganttCalendars = calendars;
  grid.ganttDependencies = dependencies;
  grid.columns = columns;
  grid.hideColumns = [...initiallyHiddenColumnProps];

  root.appendChild(grid);
  parent.appendChild(root);

  grid.source = tasks.map((task) => ({ ...task }));

  return () => root.remove();
}
Data ts
import type {
  CalendarEntity,
  DependencyEntity,
  GanttToolbarColumnOption,
  GanttTaskSourceRow,
  TaskTableColumnProp,
} from '@revolist/revogrid-enterprise';

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

export const ganttConfig = {
  id: PROJECT_ID,
  name: 'Website Redesign',
  version: '1',
  currency: 'USD',
  timeZone: 'UTC',
  primaryCalendarId: CALENDAR_ID,
  updatedAt: '2026-04-06T00:00:00Z',
  statusDate: '2026-04-06',
  zoomPreset: 'day-week' as const,
  allowTaskCreate: true,
  taskCreateRow: true,
  scheduling: {
    excludeHolidaysFromDuration: true,
  },
};

export const taskTableColumnProps: TaskTableColumnProp[] = [
  'wbs',
  'name',
  'status',
];

export const initiallyHiddenColumnProps: TaskTableColumnProp[] = ['wbs'];

const initiallyVisibleColumnProps = new Set<TaskTableColumnProp>(
  taskTableColumnProps.filter((prop) => !initiallyHiddenColumnProps.includes(prop)),
);

const allToolbarColumns = [
  { prop: 'status', label: 'Status' },
  { prop: 'name', label: 'Task' },
  { prop: 'wbs', label: 'WBS' },
] satisfies Array<Omit<GanttToolbarColumnOption, 'visible'>>;

export const toolbarColumns: GanttToolbarColumnOption[] = [...allToolbarColumns]
  .sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))
  .map((column) => ({
    ...column,
    visible: initiallyVisibleColumnProps.has(column.prop as TaskTableColumnProp),
  }));

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

export const tasks: GanttTaskSourceRow[] = [
  {
    id: 't1', parentId: null,
    name: 'Discovery', type: 'summary',
    workflowStatus: 'done',
    startDate: '2026-04-06', endDate: '2026-04-17', duration: 10,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't2', parentId: 't1',
    name: 'Stakeholder Interviews', type: 'task',
    workflowStatus: 'done',
    startDate: '2026-04-06', endDate: '2026-04-08', duration: 3,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't3', parentId: 't1',
    name: 'Analytics Review', type: 'task',
    workflowStatus: 'done',
    startDate: '2026-04-07', endDate: '2026-04-10', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't4', parentId: 't1',
    name: 'Content Inventory', type: 'task',
    workflowStatus: 'done',
    startDate: '2026-04-09', endDate: '2026-04-14', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't5', parentId: 't1',
    name: 'Requirements Workshop', type: 'task',
    workflowStatus: 'done',
    startDate: '2026-04-13', endDate: '2026-04-16', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't6', parentId: 't1',
    name: 'Discovery Sign-off', type: 'milestone',
    workflowStatus: 'done',
    startDate: '2026-04-17', endDate: '2026-04-17', duration: 0,
    percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't7', parentId: null,
    name: 'Design', type: 'summary',
    workflowStatus: 'in-progress',
    startDate: '2026-04-20', endDate: '2026-05-08', duration: 15,
    percentDone: 55, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't8', parentId: 't7',
    name: 'Information Architecture', type: 'task',
    workflowStatus: 'done',
    startDate: '2026-04-20', endDate: '2026-04-23', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't9', parentId: 't7',
    name: 'Wireframes', type: 'task',
    workflowStatus: 'done',
    startDate: '2026-04-24', endDate: '2026-04-29', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't10', parentId: 't7',
    name: 'Design System Updates', type: 'task',
    workflowStatus: 'in-progress',
    startDate: '2026-04-27', endDate: '2026-05-01', duration: 5,
    percentDone: 70, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't11', parentId: 't7',
    name: 'Visual Design', type: 'task',
    workflowStatus: 'in-progress',
    startDate: '2026-04-30', endDate: '2026-05-07', duration: 6,
    percentDone: 45, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't12', parentId: 't7',
    name: 'Prototype Review', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-05', endDate: '2026-05-07', duration: 3,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't13', parentId: 't7',
    name: 'Design Approval', type: 'milestone',
    workflowStatus: 'not-started',
    startDate: '2026-05-08', endDate: '2026-05-08', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't14', parentId: null,
    name: 'Development', type: 'summary',
    workflowStatus: 'not-started',
    startDate: '2026-05-11', endDate: '2026-06-05', duration: 20,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't15', parentId: 't14',
    name: 'Frontend Shell', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-11', endDate: '2026-05-15', duration: 5,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't16', parentId: 't14',
    name: 'CMS Integration', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-11', endDate: '2026-05-20', duration: 8,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't17', parentId: 't14',
    name: 'Reusable Page Sections', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-18', endDate: '2026-05-27', duration: 8,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't18', parentId: 't14',
    name: 'Search Experience', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-19', endDate: '2026-05-26', duration: 6,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't19', parentId: 't14',
    name: 'Analytics Events', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-25', endDate: '2026-05-29', duration: 5,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't20', parentId: 't14',
    name: 'Accessibility Pass', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-05-28', endDate: '2026-06-02', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't21', parentId: 't14',
    name: 'Performance Tuning', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-06-01', endDate: '2026-06-04', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't22', parentId: 't14',
    name: 'Feature Complete', type: 'milestone',
    workflowStatus: 'not-started',
    startDate: '2026-06-05', endDate: '2026-06-05', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't23', parentId: null,
    name: 'QA and Release Prep', type: 'summary',
    workflowStatus: 'not-started',
    startDate: '2026-06-08', endDate: '2026-06-18', duration: 9,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't24', parentId: 't23',
    name: 'Test Plan', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-06-08', endDate: '2026-06-10', duration: 3,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't25', parentId: 't23',
    name: 'Cross-browser QA', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-06-10', endDate: '2026-06-15', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't26', parentId: 't23',
    name: 'Content QA', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-06-11', endDate: '2026-06-16', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't27', parentId: 't23',
    name: 'Release Candidate', type: 'milestone',
    workflowStatus: 'not-started',
    startDate: '2026-06-18', endDate: '2026-06-18', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't28', parentId: null,
    name: 'Launch', type: 'task',
    workflowStatus: 'not-started',
    startDate: '2026-06-19', endDate: '2026-06-23', duration: 3,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't29', parentId: null,
    name: 'Post-launch Review', type: 'milestone',
    workflowStatus: 'not-started',
    startDate: '2026-06-26', endDate: '2026-06-26', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
];

export const dependencies: DependencyEntity[] = [
  { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't5', type: 'finish-to-start', lagDays: 0 },
  { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't5', type: 'finish-to-start', lagDays: 0 },
  { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 0 },
  { id: 'd4', predecessorTaskId: 't5', successorTaskId: 't6', type: 'finish-to-start', lagDays: 0 },
  { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 1 },
  { id: 'd6', predecessorTaskId: 't8', successorTaskId: 't9', type: 'finish-to-start', lagDays: 0 },
  { id: 'd7', predecessorTaskId: 't9', successorTaskId: 't11', type: 'finish-to-start', lagDays: 0 },
  { id: 'd8', predecessorTaskId: 't10', successorTaskId: 't12', type: 'finish-to-start', lagDays: 0 },
  { id: 'd9', predecessorTaskId: 't11', successorTaskId: 't13', type: 'finish-to-start', lagDays: 0 },
  { id: 'd10', predecessorTaskId: 't12', successorTaskId: 't13', type: 'finish-to-start', lagDays: 0 },
  { id: 'd11', predecessorTaskId: 't13', successorTaskId: 't15', type: 'finish-to-start', lagDays: 1 },
  { id: 'd12', predecessorTaskId: 't15', successorTaskId: 't17', type: 'finish-to-start', lagDays: 0 },
  { id: 'd13', predecessorTaskId: 't16', successorTaskId: 't18', type: 'finish-to-start', lagDays: 0 },
  { id: 'd14', predecessorTaskId: 't17', successorTaskId: 't20', type: 'finish-to-start', lagDays: 0 },
  { id: 'd15', predecessorTaskId: 't18', successorTaskId: 't19', type: 'finish-to-start', lagDays: 0 },
  { id: 'd16', predecessorTaskId: 't19', successorTaskId: 't21', type: 'finish-to-start', lagDays: 0 },
  { id: 'd17', predecessorTaskId: 't20', successorTaskId: 't21', type: 'finish-to-start', lagDays: 0 },
  { id: 'd18', predecessorTaskId: 't21', successorTaskId: 't22', type: 'finish-to-start', lagDays: 0 },
  { id: 'd19', predecessorTaskId: 't22', successorTaskId: 't24', type: 'finish-to-start', lagDays: 1 },
  { id: 'd20', predecessorTaskId: 't24', successorTaskId: 't25', type: 'finish-to-start', lagDays: 0 },
  { id: 'd21', predecessorTaskId: 't24', successorTaskId: 't26', type: 'finish-to-start', lagDays: 0 },
  { id: 'd22', predecessorTaskId: 't25', successorTaskId: 't27', type: 'finish-to-start', lagDays: 0 },
  { id: 'd23', predecessorTaskId: 't26', successorTaskId: 't27', type: 'finish-to-start', lagDays: 0 },
  { id: 'd24', predecessorTaskId: 't27', successorTaskId: 't28', type: 'finish-to-start', lagDays: 0 },
  { id: 'd25', predecessorTaskId: 't28', successorTaskId: 't29', type: 'finish-to-start', lagDays: 2 },
];
Vue vue
<template>
  <section class="gantt-basic-demo">
    <RevoGrid
      class="gantt-basic-grid"
      hide-attribution
      :can-move-columns="true"
      :theme="isDark ? 'darkCompact' : 'compact'"
      :plugins="plugins"
      :source="tasks"
      :columns="columns"
      :hide-columns.prop="hiddenColumns"
      :gantt.prop="ganttConfig"
      :gantt-dependencies.prop="dependencies"
      :gantt-calendars.prop="calendars"
    />
  </section>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentThemeVue } from '../composables/useRandomData';
import { calendars as basicCalendars, dependencies as basicDependencies, ganttConfig as basicGanttConfig, initiallyHiddenColumnProps, tasks as basicTasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentThemeVue();

const plugins = [GanttPlugin];
const ganttConfig = ref(basicGanttConfig);
const calendars = ref(basicCalendars);
const tasks = ref(basicTasks.map((task) => ({ ...task })));
const dependencies = ref(basicDependencies);
const hiddenColumns = ref([...initiallyHiddenColumnProps]);

const columns = ref(taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop)));
</script>
React tsx
// src/components/gantt/GanttBasic.tsx
import React, { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars, dependencies, ganttConfig, initiallyHiddenColumnProps, tasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();
const plugins = [GanttPlugin];

function GanttBasic() {
  const project = useMemo(() => ganttConfig, []);
  const source = useMemo(() => tasks.map((task) => ({ ...task })), []);
  const hiddenColumns = useMemo(() => [...initiallyHiddenColumnProps], []);
  const columns = useMemo(
    () => taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop)),
    [],
  );

  return (
    <section className="gantt-basic-demo">
      <RevoGrid
        className="gantt-basic-grid"
        theme={isDark() ? 'darkCompact' : 'compact'}
        hideAttribution
        canMoveColumns
        plugins={plugins}
        source={source}
        columns={columns}
        hideColumns={hiddenColumns}
        gantt={project}
        ganttDependencies={dependencies}
        ganttCalendars={calendars}
      />
    </section>
  );
}

export default GanttBasic;
Angular ts
// src/components/gantt/GanttBasicAngular.ts
import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars as basicCalendars, dependencies as basicDependencies, ganttConfig as basicGanttConfig, initiallyHiddenColumnProps, tasks as basicTasks, taskTableColumnProps } from './gantt-basic-data';

@Component({
  selector: 'gantt-basic-grid',
  standalone: true,
  // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
  schemas: [NO_ERRORS_SCHEMA],
  imports: [RevoGrid],
  template: `
    <section class="gantt-basic-demo">
      <revo-grid
        class="gantt-basic-grid"
        [theme]="theme"
        [hideAttribution]="true"
        [canMoveColumns]="true"
        [plugins]="plugins"
        [source]="tasks"
        [columns]="columns"
        [hideColumns]="hiddenColumns"
        [gantt]="ganttConfig"
        [ganttDependencies]="dependencies"
        [ganttCalendars]="calendars"
      ></revo-grid>
    </section>
  `,
  styleUrls: ['./gantt-basic.css'],
  encapsulation: ViewEncapsulation.None,
})
export class GanttBasicGridComponent {
  theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
  plugins = [GanttPlugin];

  ganttConfig = basicGanttConfig;
  calendars = basicCalendars;
  tasks = basicTasks.map((task) => ({ ...task }));
  dependencies = basicDependencies;
  hiddenColumns = [...initiallyHiddenColumnProps];

  columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));
}
  1. Complete installation for React.

  2. Create the component. Keep project collections and columns stable with useMemo so ordinary React renders do not replace Gantt state unnecessarily.

    import { useMemo } from 'react';
    import { RevoGrid } from '@revolist/react-datagrid';
    import {
    GanttPlugin,
    createDefaultTaskTableColumn,
    type CalendarEntity,
    type DependencyEntity,
    type GanttPluginConfig,
    type GanttTaskSourceRow,
    } from '@revolist/revogrid-enterprise';
    import '@revolist/revogrid-pro/dist/revogrid-pro.css';
    import '@revolist/revogrid-enterprise/dist/revogrid-enterprise.css';
    export default function ProjectGantt() {
    const plugins = useMemo(() => [GanttPlugin], []);
    const project = useMemo<GanttPluginConfig>(() => ({
    id: 'website-launch',
    name: 'Website launch',
    version: '1',
    currency: 'USD',
    timeZone: 'UTC',
    primaryCalendarId: 'standard',
    updatedAt: '2026-07-14T00:00:00.000Z',
    zoomPreset: 'day-week',
    }), []);
    const calendars = useMemo<CalendarEntity[]>(() => [{
    id: 'standard', name: 'Standard', timeZone: 'UTC',
    workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8,
    }], []);
    const source = useMemo<GanttTaskSourceRow[]>(() => [
    { id: 'design', name: 'Design', startDate: '2026-07-14', duration: 3, percentDone: 50, calendarId: 'standard' },
    { id: 'build', name: 'Build', startDate: '2026-07-17', duration: 5, percentDone: 0, calendarId: 'standard' },
    ], []);
    const dependencies = useMemo<DependencyEntity[]>(() => [{
    id: 'design-to-build', predecessorTaskId: 'design', successorTaskId: 'build', type: 'FS', lagDays: 0,
    }], []);
    const columns = useMemo(() => [
    createDefaultTaskTableColumn('wbs'),
    createDefaultTaskTableColumn('name'),
    createDefaultTaskTableColumn('startDate'),
    createDefaultTaskTableColumn('duration'),
    createDefaultTaskTableColumn('percentDone'),
    createDefaultTaskTableColumn('predecessors'),
    ], []);
    return (
    <RevoGrid
    className="project-gantt"
    plugins={plugins}
    gantt={project}
    ganttCalendars={calendars}
    ganttDependencies={dependencies}
    columns={columns}
    source={source}
    />
    );
    }
  3. Give .project-gantt a fixed or flex-derived height.

    .project-gantt { display: block; width: 100%; height: 640px; }

Continue with the Gantt tutorial and application state guide.