Skip to main content
Events are fired after an action has been committed to the store. Subscribe using api.on(event, handler). To intercept and potentially cancel an action before it is applied, use api.intercept() instead.
function init(api) {
  api.on("update-task", ({ id }) => {
    console.log("Task updated:", id);
  });
}

add-task

Fired after a new task is added to the chart.
id
string | number
The ID of the newly created task.
mode
'child' | 'before' | 'after'
The insertion mode used to place the task relative to the target.
api.on("add-task", ({ id, mode }) => {
  if (mode === "child") {
    // A child task was added — the parent may need updating
    const task = api.getTask(id);
    console.log("Child added under parent:", task.parent);
  }

  // Auto-open the editor after adding a task
  api.exec("show-editor", { id });
});

update-task

Fired after a task’s properties are changed.
id
string | number
The ID of the updated task.
api.on("update-task", ({ id }) => {
  const task = api.getTask(id);
  console.log("Updated:", task.text, "progress:", task.progress);
});

delete-task

Fired after a task is deleted.
id
string | number
The ID of the deleted task.
source
string | number
The ID of the sibling or parent task that was adjacent to the deleted task. Useful for recalculating aggregated values after deletion.
api.on("delete-task", ({ id, source }) => {
  console.log("Deleted task:", id, "adjacent:", source);
});

move-task

Fired when a task is moved to a new position in the task tree (reordering in the grid) or dragged along the timeline.
id
string | number
The ID of the moved task.
source
string | number
The original parent or sibling ID of the task before the move.
mode
'before' | 'after' | 'child' | 'up' | 'down'
How the task was repositioned relative to the target.
inProgress
boolean
true while a drag is still in progress (live preview). false when the move is finalized. Filter on inProgress: false to perform side-effects only once.
api.on("move-task", ({ id, source, mode, inProgress }) => {
  // Only act on the final move, not every drag frame
  if (inProgress) return;

  const task = api.getTask(id);
  if (task.parent !== source) {
    // Task moved to a different parent
    console.log("Reparented:", id, "from", source, "to", task.parent);
  }
});

copy-task

Fired after a task is duplicated (e.g. via the context menu Copy action).
id
string | number
The ID of the newly created copy.
api.on("copy-task", ({ id }) => {
  console.log("Task copied, new id:", id);
});

drag-task

Fired continuously while a task bar is being dragged on the chart (both move and resize). Also fires once when the drag ends with inProgress: false.
id
string | number
The ID of the task being dragged.
left
number
Current pixel offset from the left edge of the chart area.
width
number
Current pixel width of the task bar.
top
number | undefined
Present when the task is being reordered vertically in the grid. undefined when the task is being moved or resized horizontally on the chart.
inProgress
boolean
true during a live drag; false on the final drop.
// Intercept to prevent dragging summary tasks horizontally
api.intercept("drag-task", ({ id, top }) => {
  if (typeof top === "undefined" && api.getTask(id).type === "summary") {
    return false;
  }
});

// Use api.on to observe drag events
api.on("drag-task", ({ id, inProgress }) => {
  if (!inProgress) console.log("Drag finished for:", id);
});

sort-tasks

Fired after the task list is sorted by a column.
key
string
The column key used to sort (e.g. "text", "start", "duration").
order
'asc' | 'desc'
The sort direction.
add
boolean
When true, this sort is being added to an existing multi-column sort.
api.on("sort-tasks", ({ key, order }) => {
  console.log(`Sorted by ${key} ${order}`);
  // Update custom sort indicator UI
  setSortConfig({ key, order });
});

show-editor

Fired when the editor is about to open for a task, or when it is closed.
id
string | number | null
The ID of the task being edited. null when the editor is closing.
api.on("show-editor", ({ id }) => {
  if (id) {
    const task = api.getTask(id);
    // Adjust editor fields based on task type
    if (task.type === "milestone") disableProgressField();
  }
});

// Intercept to replace with a custom form
api.intercept("show-editor", ({ id }) => {
  if (id) {
    openMyCustomForm(id);
    return false; // prevent the built-in editor from opening
  }
});

zoom-scale

Fired after the zoom level changes (e.g. via Ctrl+scroll).
dir
number
The direction of the zoom: positive values zoom in, negative values zoom out.
offset
number
The horizontal pixel offset of the mouse pointer at the time of the zoom, used to keep the view centered on the cursor position.
api.on("zoom-scale", () => {
  const { zoom } = api.getState();
  console.log("Current zoom:", zoom);
});

request-data

Fired when the Gantt needs to lazy-load child data for a task node that has not yet been fetched from the server.
id
string | number
The ID of the parent task whose children need to be loaded.
After loading the data, respond with api.exec('provide-data', ...) to deliver the results.
function init(api) {
  api.on("request-data", (ev) => {
    fetch(`/api/tasks/${ev.id}`)
      .then((res) => res.json())
      .then((data) => {
        api.exec("provide-data", {
          id: ev.id,
          data: {
            tasks: data.tasks,
            links: data.links,
          },
        });
      });
  });
}

select-task

Fired after the task selection changes.
id
string | number
The ID of the task that was clicked or selected.
toggle
boolean
true when Ctrl/Cmd was held during the click (multi-select toggle).
range
boolean
true when Shift was held during the click (range selection).
show
boolean
true when the chart should scroll to bring the selected task into view.
api.on("select-task", ({ id }) => {
  const task = api.getTask(id);
  console.log("Selected:", task.text);
});

open-task

Fired when a summary task node is expanded or collapsed in the grid.
id
string | number
The ID of the task being toggled.
mode
boolean
true to expand, false to collapse.
api.on("open-task", ({ id, mode }) => {
  console.log(mode ? "Expanded:" : "Collapsed:", id);
});

Fired after a dependency link is created between two tasks.
api.on("add-link", ({ link }) => {
  console.log(`Link: ${link.source}${link.target} (${link.type})`);
});

Fired after a dependency link is updated.
id
string | number
The ID of the updated link.
The updated link properties.
api.on("update-link", ({ id, link }) => {
  console.log("Link updated:", id, link);
});

Fired after a dependency link is deleted.
id
string | number
The ID of the deleted link.
api.on("delete-link", ({ id }) => {
  console.log("Link deleted:", id);
});

Build docs developers (and LLMs) love