Configuration Reference
Source code
// src/components/gantt/GanttBasic.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';
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();
}
import type {
CalendarEntity,
DependencyEntity,
GanttToolbarColumnOption,
GanttTaskSourceRow,
TaskTableColumnProp,
} from '@revolist/gantt';
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 },
];
<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/gantt';
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>
// src/components/gantt/GanttBasic.tsx
import React, { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';
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;
// 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/gantt';
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));
}
Public config entry points:
GanttPluginConfigweekStartsOn?: 0 | 1controls week header/tick alignment. Omit for Sunday (0); set1for Monday.timelinePrecision?: 'day' | 'hour'controls the default precision for timeline task create, move, and resize interactions. Use'hour'withzoomPreset: 'hour-day'orzoom.defaultLevelId: 'hour-day'for hour-scale planning.snap?: { unit?: 'day' | 'hour'; workingTime?: boolean }controls interaction snapping.unit: 'hour'keeps interactions on hour boundaries;workingTime: trueor omitted skips holidays, closed weekdays, and closedcalendar.workingHours.calendars?: CalendarEntity[]can include intradayworkingHourssuch as{ start: '09:00', end: '17:00' }plushoursPerDayfor hour-mode snapping and scheduling.durationSettings?: DurationSettingscontrols the fixed/automatic display unit, compact display precision throughmaximumFractionDigits(default1), and conversions throughhoursPerDay,hoursPerWeek, anddaysPerMonth. See Duration Units and Conversion.allowedTaskTypes?: TaskType[]restricts the choices in packaged Task Type column and dialog editors. Omit it to allowtask,milestone, andsummary; use['task']to prevent users from converting tasks to milestones or summaries.labels?: GanttLabelsConfigcustomizes option labels, validation errors, scheduler warnings, and task-editor text from one project-level object. See Labels, Errors, and Warnings.dateFormats?: GanttDateFormatConfigcontrols task-table, tooltip, editor, and timeline date presentation and parsing. See Date Formatting.visuals.percentDoneMode?: 'number' | 'bar' | 'circle'controls the project default for the managed% Donetask-table cell. It defaults tobar;{ prop: 'percentDone', mode: 'circle' }overrides it per column. See Actuals and Progress.taskCreateRow?: booleanshows an opt-in pinned bottom “Add new task” row. It requiresallowTaskCreate: trueand is hidden for read-only or resource-planning views. See Add Task Row forGanttAddTaskRowPluginbehavior andisGanttAddTaskRow()usage.
GanttSchedulingConfigGanttResourcePlanningConfigGanttVisualConfig
Duration Settings
Section titled “Duration Settings”durationSettings.defaultUnit and defaultWorkUnit accept every DurationUnit or 'auto'. Duration, Remaining Duration, and Work are stored as hours. defaultUnit controls task-span quantities while defaultWorkUnit independently controls Work; task durationUnit and workUnit win. auto displays sub-hour values as minutes, sub-day values as hours, and longer values as days without changing stored task data.
grid.gantt = { ...project, durationSettings: { defaultUnit: 'auto', defaultWorkUnit: 'hour', hoursPerDay: 8, hoursPerWeek: 40, daysPerMonth: 20, },};See Duration Units and Conversion for mixed task units, flexible input, elapsed durations, defaults, and conversion behavior.
Labels, Errors, and Warnings
Section titled “Labels, Errors, and Warnings”Use gantt.labels as the project-level localization and message catalog. Error and warning overrides can be strings or formatter functions. The plugin keeps the existing result contract—such as { field, code, message }—and changes only the resolved message.
grid.gantt = { ...project, labels: { errors: { taskEdit: { invalidRemainingDuration: 'Remaining duration must be a value such as 5h, 2d, 3w, or 30m.', }, taskEditor: { invalidRemainingDuration: 'Enter remaining time in hours or days.', }, dependency: { taskReferenceNotFound: ({ value }) => `No task matches "${value}".`, }, }, warnings: { scheduler: { deadlineMissed: ({ taskId, date }) => `Task ${taskId} missed its ${date} deadline.`, }, }, taskEditor: { applyLabel: 'Apply changes', status: { saveFailed: 'The task could not be saved.', }, }, },};Message groups identify the runtime surface: taskEdit for managed grid-cell edits, taskMutation for task operations and timeline interactions, assignment, dependency, and taskEditor. Scheduler issues and conflicts use warnings.scheduler. The exported DEFAULT_GANTT_ERROR_LABELS and DEFAULT_GANTT_WARNING_LABELS constants contain every supported key and the default English text.
The task-editor dialog inherits gantt.labels.taskEditor. A dialog-specific localeText option remains supported and takes precedence over the inherited project labels, which allows one editor instance to override selected text without duplicating the rest of the project locale.
Date Formatting
Section titled “Date Formatting”Managed Gantt date columns display a localized medium date by default (for example, Apr 6, 2026 with the default en-US locale). This applies consistently to Start, End, Actual Start/Finish, Early/Late Start/Finish, Constraint Date, and Deadline. ISO date-time task values such as 2026-04-06T09:00:00.000Z remain unchanged in your data; only their cell display is formatted, and the default table display intentionally omits the time.
Set gantt.dateFormats.locale, timeZone, and table to choose your own project-wide table format. table accepts standard Intl.DateTimeFormatOptions:
grid.gantt = { ...project, dateFormats: { locale: 'en-GB', timeZone: 'Europe/London', table: { day: '2-digit', month: '2-digit', year: 'numeric', }, },};For field-specific or application-defined output, provide a formatter callback. The context includes the managed field name, locale, time zone, and surface:
grid.gantt = { ...project, dateFormats: { table: (value, context) => { const date = new Date(value.length === 10 ? `${value}T00:00:00Z` : value); const prefix = context.field === 'deadlineDate' ? 'Due ' : '';
return `${prefix}${new Intl.DateTimeFormat('de-DE', { day: '2-digit', month: 'short', year: 'numeric', timeZone: context.timeZone, }).format(date)}`; }, },};Use dateFormats.tooltip and dateFormats.timeline for those surfaces. If editor text must use a non-ISO format, pair dateFormats.editor.formatter with dateFormats.editor.parser (or the shared dateFormats.parser) so edits are converted back to ISO date or UTC ISO date-time values before scheduling.
Adaptive Mobile Interactions
Section titled “Adaptive Mobile Interactions”Gantt automatically adapts pointer interactions for phones, tablets, and other coarse-pointer devices. There is no mobile-only configuration flag; the same GanttPluginConfig works across desktop and touch devices.
Mobile behavior is designed around select-then-edit:
- Mouse and trackpad users keep direct desktop interactions for moving, resizing, progress updates, dependency drawing, timeline panning, and split-panel resizing.
- Touch users tap a task bar first to select it and reveal larger resize, progress, dependency, and split handles.
- Dragging a selected task bar moves the task. Dragging a visible handle resizes, updates progress, edits splits, or creates dependencies.
- Plain touch scrolling in the task table or timeline remains scroll-first and should not move, resize, or create tasks accidentally.
- Hidden coarse-pointer handles are not hit-testable until the task is selected or interaction-active, so an edge swipe on an unselected task still behaves like navigation.
- Task editor dialogs switch to a single-column, full-viewport layout on narrow screens with larger controls for touch input.
The Gantt E2E suite includes a dedicated mobile project using an iPhone viewport. It verifies that unselected task-bar swipes do not mutate dates, tapping selects a task and exposes handles, and the task editor dialog fits a phone-sized viewport.
Canonical definitions:
packages/gantt/src/gantt/grid/gantt-plugin.types.ts
For generated signatures, see API: Gantt.