Data Model
Source code
// 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();
}
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 },
];
<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>
// 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;
// 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 rowsganttCalendars: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.tspackages/enterprise/plugins/gantt/core/domain.ts
Flat Task Source Rows
Section titled “Flat Task Source Rows”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:
durationmaps to internaldurationDays.percentDonemaps to internalprogressPercent.taskModemaps to internalmanuallyScheduled(manualorauto).statusis stored as the raw task status key, such asin-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.
Temporal Field Precision
Section titled “Temporal Field Precision”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.