Data
Tasks & Milestones
Tasks are the core data unit. Each task has a type that determines its behavior and appearance.
Task Types
| task | A regular task with start/end time and duration. |
| milestone | A zero-duration point in time (only startTime). |
| summary | A parent task whose dates are derived from its subtasks. |
| empty | A placeholder row with no dates. |
Task Properties
| id: string | Unique identifier (read-only). |
| name: string | null | Display name of the task. |
| type: TaskType | 'task' | 'milestone' | 'summary' | 'empty' |
| startTime: Date | null | Start date/time. |
| endTime: Date | null | End date/time. |
| length: Length | null | Duration (e.g. 5d, 8h). Parsed from string via Length.tryParse(). |
| progress: number | null | Completion percentage (0–100). |
| customLengthUnit: LengthUnit | null | Override for the length display unit. When null, the calendar's default unit is used. |
| color: ColorValue | Color index into the theme's taskColors array, or a custom ColorDefinition. |
| note: string | null | Free-text note / description. |
| work: Work | null | Total work effort (e.g. 40h, 5d). |
| cost: number | null | Total cost computed from resource rates and work. |
| constraintType: ConstraintType | Scheduling constraint type (default: 'asap'). |
| constraintDate: Date | null | Target date for the constraint. |
| baselineStartTime: Date | null | Baseline start date (set by saveBaseline). |
| baselineEndTime: Date | null | Baseline end date (set by saveBaseline). |
| collapsed: boolean | Whether a summary task's subtasks are collapsed. |
| warnings: string[] | Validation warnings (e.g. scheduling conflicts). |
| filtered: boolean | Whether the task is excluded by the active filter. |
| hidden: boolean | Whether the task is hidden (collapsed parent or filtered). Read-only. |
| parent: Task | null | Parent task (read-only). Null for top-level tasks. |
| level: number | Nesting depth in hierarchy (read-only). |
Task Colors
Each task has a color property that controls its visual appearance in the chart. Set it to a theme color index (0–7) or a custom ColorDefinition. The default themes provide 8 color sets: blue (0), red (1), green (2), yellow (3), purple (4), orange (5), teal (6), pink (7).
const task1 = gantt.list.getTaskById('1');
const task2 = gantt.list.getTaskById('2');
const task3 = gantt.list.getTaskById('3');
// Use theme color index (0–7)
task1.color = 0; // blue (default)
task2.color = 1; // red
task3.color = 2; // green
// Or use a fully custom color definition
task1.color = {
color1: '#dbeafe', // bar gradient top
color2: '#3b82f6', // bar gradient bottom
highlightColor: 'rgba(59, 130, 246, 0.3)', // hover overlay
borderColor: '#2563eb', // border (null = no border)
progressColor1: '#2563eb', // progress gradient top
progressColor2: '#1d4ed8', // progress gradient bottom
};
// Color-code tasks by priority
for (let i = 0; i < gantt.list.length; i++) {
const task = gantt.list.getTask(i);
const priority = task.getPropertyValue('priority');
if (priority === 'High') task.color = 1; // red
else if (priority === 'Medium') task.color = 5; // orange
else task.color = 0; // blue (default)
}To customize the color palette itself (e.g. change what index 0 looks like), see the Theming & Styles guide.
Hierarchy
Tasks support parent/child relationships. Use indent() and outdent() to change nesting, or manipulate programmatically:
// Add a subtask
const parent = gantt.list.getTaskById('1');
const child = gantt.list.getTaskById('2');
parent.addSubtask(child);
// Remove a subtask (promotes it to sibling)
parent.removeSubtask(child);
// Access subtasks
parent.subtasksLength; // number of direct children
parent.getSubtask(0); // first child
// Collapse / expand
parent.toggleCollapsed();
// Indent / outdent selected tasks
gantt.indent();
gantt.outdent();
// Move tasks up / down
gantt.moveUp();
gantt.moveDown();Task Parts
A task can be split into multiple parts (e.g. interrupted work). By default, users can create new parts by dragging on an empty area of an existing task row. Disable this with allowTaskSplitting:
// Disable creating new parts via mouse (programmatic addPart still works)
gantt.allowTaskSplitting = false;
const task = gantt.list.getTaskById('1');
// Add a second part
task.addPart(new Date('2027-01-20'), Length.parse('3d'));
// Access parts
console.log(task.partsLength); // 2
const part = task.getPart(1);
console.log(part.startTime, part.endTime);
// Remove a part
task.removePart(part);Populating the Chart (Programmatic)
The recommended way to populate the chart is the programmatic API. Use createTask() to create a properly initialized task, set its properties, then add it with addTask(). Date setters automatically normalize values to working hours:
const list = gantt.list;
list.clear(); // remove default empty rows
const design = list.createTask('1');
design.name = 'Design';
design.startTime = new Date('2027-01-05'); // normalized to start of shift (e.g. 08:00)
design.endTime = new Date('2027-01-09'); // normalized to end of shift (e.g. 17:00)
design.progress = 100;
list.addTask(design);
const dev = list.createTask('2');
dev.name = 'Development';
dev.startTime = new Date('2027-01-12');
dev.endTime = new Date('2027-01-23');
list.addTask(dev);
// Add a dependency
list.addLink(design, dev, 'finishToStart');Serialization (load / save)
Use load() and save()to persist and restore chart state (e.g. to/from a database, file, or local storage). These methods are designed as counterparts — load() expects JSON previously produced by save():
Date-only values (e.g. "2027-01-05") are also accepted and automatically normalized to working hours: startTime is moved to the beginning of the first shift (e.g. 08:00) and endTime to the end of the last shift (e.g. 17:00). Milestones are normalized to end of the working day. This makes it easy to hand-write JSON without specifying exact times.
// Save current state
const json = gantt.save();
localStorage.setItem('gantt-data', json);
// Restore saved state
const saved = localStorage.getItem('gantt-data');
if (saved) {
gantt.load(saved);
}Adding & Removing Tasks
Additional ways to add and manage tasks:
// Or add an empty row and fill it in
const empty = gantt.list.addEmptyTask();
empty.name = 'Planning';
empty.startTime = new Date('2027-01-05');
empty.endTime = new Date('2027-01-09');
// Insert an empty task at a specific position
gantt.list.insertEmptyTask(2);
// Access tasks by index or ID
const first = gantt.list.getTask(0);
const task1 = gantt.list.getTaskById('1');
console.log(gantt.list.length); // total task count
// Find tasks using a specific resource
const tasks = gantt.list.getTasksUsingResource(dev);
// Remove
gantt.list.removeTask(task);
gantt.list.removeTasks([task1, task2]);
// Clear all
gantt.list.clear();Dependencies
Dependencies (links) define scheduling relationships between tasks. When a predecessor changes, dependent tasks are automatically rescheduled.
Link Types
| finishToStart (FS) | Task B starts after Task A finishes. The most common type. |
| startToStart (SS) | Task B starts when Task A starts. |
| finishToFinish (FF) | Task B finishes when Task A finishes. |
| startToFinish (SF) | Task B finishes when Task A starts. |
// Add a dependency
const from = gantt.list.getTaskById('1');
const to = gantt.list.getTaskById('2');
const link = gantt.list.addLink(from, to, 'finishToStart');
// Add with lag (delay) or lead (negative lag)
const lag = Lag.parse('+2d');
gantt.list.addLink(from, to, 'finishToStart', lag);
// Remove a dependency
gantt.list.removeLink(link);
// Check before adding
gantt.list.existsLinkBetween(from, to); // already linked?
gantt.list.wouldCreateCycle(from, to); // would create cycle?
// Determine link type from connector sides
import { getLinkType } from '@timelinekit/core';
const type = getLinkType('finish', 'start'); // 'finishToStart'Auto-scheduling
Dependencies are automatically enforced by the scheduling engine. When a predecessor task changes (moved, resized, or its duration changes), all dependent successors are automatically rescheduled to maintain the dependency relationship. This cascade propagates through the entire dependency chain — if Task A → Task B → Task C, moving Task A automatically shifts both B and C.
The scheduling engine also respects constraints and the working calendar — successors are placed on the next available working time after the dependency is satisfied. Tasks with constraints (e.g. "Start No Earlier Than") will not be moved before their constraint date, and a warning is generated if a dependency conflict arises.
// When you move Task A, Task B is automatically rescheduled:
const taskA = gantt.list.getTaskById('1');
const taskB = gantt.list.getTaskById('2');
gantt.list.addLink(taskA, taskB, 'finishToStart');
// Moving Task A's end date forward → Task B's start shifts automatically
taskA.endTime = new Date('2027-01-15');
// taskB.startTime is now automatically >= 2027-01-15 (next working day)
// With lag: Task B starts 2 days after Task A finishes
gantt.list.addLink(taskA, taskB, 'finishToStart', Lag.parse('+2d'));Link Properties
| id: string | Unique identifier (read-only). |
| from: Task | Source (predecessor) task (read-only). |
| to: Task | Target (successor) task (read-only). |
| type: TaskLinkType | 'finishToStart' | 'startToStart' | 'finishToFinish' | 'startToFinish' |
| lag: Lag | Time offset. Positive = delay, negative = lead. |
Resources
Resources represent people, equipment, or materials assigned to tasks. Each assignment has a capacity (allocation percentage).
// Define resources
const dev = new Resource(null, 'Alice', 'unique');
const designer = new Resource(null, 'Bob', 'unique');
gantt.resources.addResource(dev);
gantt.resources.addResource(designer);
// Look up a resource
const res = gantt.resources.getResourceById('r1');
const first = gantt.resources.getResource(0);
console.log(gantt.resources.length);
// Remove a resource
gantt.resources.removeResource(dev);
// Assign a resource to a task
const task = gantt.list.getTaskById('1');
task.addResource(null, dev, 100); // 100% allocation
// Read an existing assignment
const assignment = task.getResourceByResourceId(dev.id);
assignment.capacity = 50; // change to 50%
// Remove a resource assignment
task.removeResource(assignment);Resource Properties
| id: string | Unique identifier (read-only). |
| name: string | Display name. |
| type: ResourceType | 'unique' (named person) or 'generic' (interchangeable role). |
| rate: Rate | null | Cost rate (value + type: 'perDay' or 'perHour'). |
| fixedCostPerUse: number | One-time cost each time the resource is used. |
| fixedCostPerResource: number | Fixed cost per resource assignment. |
| avatarIconUrl: string | null | URL for avatar icon in the UI. |
Work & Cost
Each task tracks work effort and cost, calculated from resource assignments:
| task.work: Work | null | Total work effort (e.g. 40h, 5d). |
| task.cost: number | null | Total cost computed from resource rates and work. |
Constraints
Constraints control how the scheduling engine positions a task relative to a target date.
Constraint Types
| asap | As Soon As Possible (default). Task is scheduled at the earliest possible date. |
| alap | As Late As Possible. Task is scheduled at the latest date without delaying successors. |
| mso | Must Start On. Task must start on the constraint date. |
| mfo | Must Finish On. Task must finish on the constraint date. |
| snet | Start No Earlier Than. Task cannot start before the constraint date. |
| snlt | Start No Later Than. Task cannot start after the constraint date. |
| fnet | Finish No Earlier Than. Task cannot finish before the constraint date. |
| fnlt | Finish No Later Than. Task cannot finish after the constraint date. |
const task = gantt.list.getTaskById('1');
task.constraintType = 'snet';
task.constraintDate = new Date('2027-02-01');Custom Properties
Add arbitrary fields to tasks for domain-specific data (e.g. priority, department, WBS code). To display custom properties in the sheet, add a custom column.
const task = gantt.list.getTaskById('1');
// Add a custom property
task.addProperty(new CustomProperty('priority', 'High'));
// Read / write
task.getPropertyValue('priority'); // 'High'
task.setPropertyValue('priority', 'Low');
// Look up by name
const prop = task.getPropertyByName('priority');
// Rename or remove
task.renameProperty('priority', 'urgency');
task.removeProperty(prop);