ApexGantt 3.15.0 is out. Taken together with the two releases just before it, this is the update that turns the ApexGantt task list from a simple label column into a full data grid, and adds a stack of scheduling features that close the gap with heavyweight Gantt suites. If you have not upgraded since the 3.13 line, here is the short version: the task list now sorts, filters, and groups; columns resize, reorder, and auto-size; tasks can be split into worked segments; the chart can save and restore where the user left off; you can draw new tasks on the timeline; and export produces SVG, PNG, or PDF. Every bar gesture now works with touch and pen, and the TypeScript types finally cover all of it.

3.15.0 itself is a small, mostly additive release on top of that: clicking a task row can now scroll its bar into view, the edge scroll chevrons became opt-in, and two rendering bugs are fixed. This post covers everything new across the arc, grouped by feature rather than by version number.

What's new at a glance

  • The task list is a real data grid: hierarchy-preserving sorting, quick and advanced filtering, grouping, and columns you can resize, reorder, and auto-size, plus six new built-in columns.
  • Split tasks: one row, several worked segments separated by gaps.
  • UI-state persistence: capture and restore zoom, scroll, collapse, selection, sort, filter, and column layout.
  • Draw-to-create, scroll-to-task, and multi-format export (SVG, PNG, PDF).
  • Touch and pen support for every editing gesture, via Pointer Events.
  • New in 3.15.0: click a row to scroll its bar into view (scrollToTaskOnRowClick), scroll chevrons are now opt-in, and fixes for custom accessor columns and empty-row alignment.
  • TypeScript: the bundled declarations now match the shipped API, so the whole grid feature set is correctly typed.

See it live

The chart below runs the real ApexGantt the site ships. Click a column header to sort, drag a column edge to resize it or drag a header to reorder, and click any row to scroll its bar into view. The Build task is split into two worked segments.

Try it: click a column header to sort (Shift-click adds a second key), drag a column's right edge to resize or drag a header to reorder, and click any row to scroll its bar into view. The Build task is split into two worked segments.

The task list is now a real data grid

This is the centerpiece of the release. The panel on the left stopped being a static label column and became a grid you can sort, filter, group, and reshape.

Sorting is hierarchy-preserving. You can sort by any value column, and the tree is never flattened: siblings reorder within their parent, and summary rows sort by their rolled-up span.

new ApexGantt(el, {
  series: tasks,
  sortBy: { key: ColumnKey.Name, direction: 'asc' },
  // multi-key: first key wins, ties break on the next
  // sortBy: [{ key: ColumnKey.Progress, direction: 'desc' }, { key: ColumnKey.Name }],
});

gantt.toggleSort(ColumnKey.Name);                  // header-click cycle: asc, desc, none
gantt.toggleSort(ColumnKey.Start, { append: true }); // Shift+click adds a secondary key
gantt.clearSort();

Filtering has two surfaces, both view-only. A quick-filter search box, and an advanced builder that composes field/operator/value conditions with All (AND) or Any (OR). A task is kept when it matches or has a matching descendant, so ancestors stay visible for context. Filtering changes which rows render, never the underlying data.

new ApexGantt(el, {
  series: tasks,
  enableQuickFilter: true,
  enableFilterBuilder: true,
  filterRules: {
    match: 'all',
    rules: [{ field: 'progress', operator: 'lessThan', value: 100 }],
  },
});

Grouping buckets tasks under collapsible headers with a member count. While grouping is active the tree is suspended and every task shows flat under its group; clearing it restores the exact prior hierarchy.

gantt.groupBy(ColumnKey.Progress);
gantt.groupBy({ field: 'status', label: (v) => `Status: ${v}`, direction: 'desc' });
gantt.clearGrouping();

Sort, filter, and group all compose with each other, and each emits an event (sortChange, filterChange, groupChange).

Columns resize, reorder, and auto-size. Drag a column header's trailing edge to pin an exact width, drag the header itself to reorder, and by default each column sizes to fit its content so nothing clips. There are also six new built-in columns backed by existing data: Predecessors, Successors, Assignees, BaselineStart, BaselineEnd, and BaselineVariance.

gantt.setColumnWidth(ColumnKey.Name, 260);
gantt.setColumnOrder([ColumnKey.Name, ColumnKey.Progress, ColumnKey.StartTime]);
gantt.getColumnWidths();

Split tasks

A single task can now be split into several worked segments separated by gaps, on one row: work Monday to Wednesday, pause, resume Friday.

new ApexGantt(el, {
  series: [
    {
      id: 't1',
      name: 'Build',
      segments: [
        { startTime: '2026-06-01', endTime: '2026-06-04' },
        { startTime: '2026-06-08', endTime: '2026-06-12' },
      ],
    },
  ],
});

gantt.splitTask('t1', '2026-06-08', { resumeAt: '2026-06-12' }); // or split at runtime
gantt.isSplit('t1');

The task's start and end become the envelope of its segments and are derived automatically, so summary rollups, dependencies, the timeline header, and the Duration column all keep working. The bar draws one filled piece per segment joined by a thin connector, and dragging moves all segments together. See the split tasks guide for the full API.

Save and restore where the user left off

getState() and setState() capture and restore a serializable snapshot of the view: zoom, scroll, collapse, selection, sort, filter, manual column widths, and column order. Persist it to your own backend, or let the chart use localStorage automatically.

const saved = gantt.getState();   // serializable snapshot
gantt.setState(saved);
gantt.setState({ collapsed: ['phase-1'] }, { silent: true }); // partial, no events

// or automatic localStorage persistence
new ApexGantt(el, { series: tasks, persistState: true });
new ApexGantt(el, { series: tasks, persistState: { key: 'project-42-gantt' } });

setState() accepts a partial state, re-renders once, and the snapshot is versioned and SSR-safe.

Draw tasks, scroll to tasks, and export

Draw-to-create. With enableDrawTask: true, drag across empty timeline space to sweep out a date range; on release a task is created, snapped to your snapUnit. It flows through the same veto hook and command bus as every other add, so it is undoable.

Scroll to a task. gantt.scrollToTask(id) brings a task's bar into view, and works even when the target row is virtualized out of the DOM. New in 3.15.0, you can wire this to row clicks:

new ApexGantt(el, { series: tasks, scrollToTaskOnRowClick: true });

Clicking a task-list row now scrolls that task's bar into view. It composes with selection (a single click both selects the row and reveals its bar), and it ignores clicks on the selection checkbox, the toggle chevron, and active inline-edit inputs, so those controls keep working.

Multi-format export. The toolbar export button and gantt.exportChart() now produce SVG, PNG, or PDF. The PDF path is dependency-free.

await gantt.exportChart('pdf'); // or 'png' / 'svg'

Touch and pen now work everywhere

Every bar interaction (drag, resize, progress-drag, dependency-draw, and the panel split-bar) was migrated from mouse handlers to Pointer Events, with touch-action: none and per-gesture pointer ownership. Tablets, touchscreens, and pens now work for all editing gestures, with no API change on your side.

TypeScript: the types now match the API

If you use ApexGantt from TypeScript, this is the most important line in the release. The bundled declaration file had been re-bundled from stale intermediate declarations, so it froze at an older API surface: every feature in the grid work above shipped with a working runtime but missing types, and consumers got "property does not exist" errors when using sorting, filtering, grouping, column methods, split tasks, state, or export. The declarations now match the shipped API, and a stray internal @apex/commons import that broke type resolution was inlined out. If you are on an older 3.1x version from TypeScript, upgrade to pick up the correct types. JavaScript usage was never affected.

What changed: two new defaults

No options were removed or renamed, but two defaults flipped across this release line. Both are one-line reversals if you want the old behavior.

DefaultNowRestore the old behavior
autoSizeColumnstrue (columns size to content, panel grows to fit)autoSizeColumns: false
enableScrollButtonsfalse (edge scroll chevrons are opt-in)enableScrollButtons: true

3.15.0 also fixes two rendering bugs: a custom columnConfig column with an accessor (and no render) was blank until an interaction re-rendered the row, and is now correct on first paint; and the filler empty rows in the two panes could drift by one row when the "+ Add task" row was enabled, so hover and striping now line up across both panes.

How to upgrade

Install the latest from npm, or bump the pinned version on your CDN link:

npm install apexgantt@latest

Everything except the two defaults above is additive, so most projects upgrade with no code changes. TypeScript projects gain correct types for the whole grid API. See the installation and usage docs for setup, the task management guide for the grid and CRUD API, and the ApexGantt product page for live examples.

Summary

ApexGantt 3.15.0 caps a release line that reshapes the task list into a proper data grid: hierarchy-preserving sorting, quick and advanced filtering, grouping, and columns you can resize, reorder, and auto-size. Around that it adds split tasks, UI-state persistence, draw-to-create, scroll-to-task, multi-format export, and full touch and pen support, and it finally ships correct TypeScript declarations for all of it. 3.15.0's own additions are small and additive: click a row to scroll its bar into view, opt-in scroll chevrons, and two rendering fixes. Two defaults changed (autoSizeColumns and enableScrollButtons), both reversible in one line, and nothing was removed. Run npm install apexgantt@latest and the new grid is yours.

Frequently asked questions

What is new in ApexGantt 3.15.0?

The big change across this release line is that the task list became a full data grid: sortable, filterable, and groupable, with resizable, reorderable, auto-sizing columns and six new built-in columns. It also adds split tasks, UI-state persistence, draw-to-create, scroll-to-task, and SVG/PNG/PDF export, and every bar gesture now works with touch and pen. 3.15.0 itself adds clicking a task row to scroll its bar into view, makes the edge scroll chevrons opt-in, and fixes custom accessor columns and empty-row alignment.

Are there breaking changes when upgrading to 3.15.0?

No API was removed or renamed, but two defaults changed. autoSizeColumns now defaults to true, so columns size to their content and the panel grows to fit; set autoSizeColumns: false to keep the old fixed-width layout. enableScrollButtons now defaults to false, so the edge scroll chevrons are opt-in; set enableScrollButtons: true to restore them. Everything else is additive.

How do I upgrade?

Run npm install apexgantt@latest, or bump the pinned version on your CDN link. TypeScript users especially should upgrade: 3.14.1 fixed the bundled type declarations, which had drifted and were missing types for the entire grid feature set, so the whole API is now correctly typed.

Does the ApexGantt task list support sorting and filtering now?

Yes. The task list is a full data grid. Sorting is hierarchy-preserving (siblings reorder within each parent, the tree is never flattened). Filtering has both a quick search box and an advanced All/Any rule builder, and it is view-only, so it never mutates your task data. Grouping buckets tasks under collapsible headers. All three compose and each emits an event.

Can a task be split into multiple segments?

Yes. Pass a segments array of worked spans and the bar draws one piece per segment joined by a thin connector, with progress filling left to right. The task's start and end become the envelope of the segments and are derived automatically, so summary rollups, dependencies, and the Duration column keep working. You can also split at runtime with gantt.splitTask().