Skip to content

Data Model

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, 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;

  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',
  zoomPreset: 'week' as const,
  allowTaskCreate: true,
};

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

const initiallyVisibleColumnProps = new Set<TaskTableColumnProp>(taskTableColumnProps);

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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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',
    status: '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"
      :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, tasks as basicTasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentThemeVue();

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

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, tasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();

function GanttBasic() {
  const project = useMemo(() => ganttConfig, []);
  const source = useMemo(() => tasks.map((task) => ({ ...task })), []);

  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={[GanttPlugin]}
        source={source}
        columns={columns}
        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, 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"
        [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;

  columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));
}

This page is for wiring the minimum data surface.

Required entry points on HTMLRevoGridElement:

  • gantt: project config (GanttPluginConfig)
  • source: flat task rows
  • ganttCalendars: CalendarEntity[]

Optional linked collections:

  • ganttDependencies: DependencyEntity[]
  • ganttResources: ResourceEntity[]
  • ganttAssignments: AssignmentEntity[]
  • ganttBaselines: BaselineSnapshot[]

Public shape is declared in:

  • packages/enterprise/plugins/gantt/grid/gantt-plugin.types.ts
  • packages/enterprise/plugins/gantt/core/domain.ts

Gantt reads task data from flat grid rows. Required fields are id, name, startDate, and either duration or endDate.

The public source row names match task-table editing conventions:

  • duration maps to internal durationDays.
  • percentDone maps to internal progressPercent.
  • taskMode maps to internal manuallyScheduled (manual or auto).
  • status is stored as the raw task status key, such as in-progress.

When both duration and endDate are present, duration is the scheduling input and Gantt resolves endDate from startDate + duration. This matches task-table editing, where duration edits drive the finish date. Use endDate without duration when the finish date should be the authored input.

Projected grid rows remain display-ready. GanttGridRow.status is the human-readable status label, while GanttGridRow.statusKey is the raw status key. Custom source fields are preserved by task id across recalculation and structural task changes unless the row is replaced without those fields.

Task temporal fields (startDate, endDate, actualStartDate, actualFinishDate) accept:

  • ISO date: YYYY-MM-DD
  • UTC ISO datetime: YYYY-MM-DDTHH:mm:ss.sssZ

Runtime normalization rules:

  • Datetime input is preserved and used for intraday scheduling precision.
  • Date-only input is normalized to T00:00:00Z.

For new integrations, prefer explicit UTC datetime values when you need hour/minute planning behavior.