Sorting and Filtering

The ApexGantt task list behaves like a data grid: it can be sorted by any value column and filtered down to the rows that matter. Sorting reorders rows within the hierarchy; filtering changes which rows render. Neither touches the underlying task data.

Sorting

Sorting is hierarchy-preserving. Siblings reorder within each parent, the tree is never flattened, and summary rows sort by their rolled-up span.

Initial sort

Set the sortBy option to one SortCriterion or an array of them. The chart defaults to start-time ascending; pass [] for natural (input) order.

const gantt = new ApexGantt(el, {
  series: tasks,
  sortBy: { key: ColumnKey.Name, direction: 'asc' },
})

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

Sorting at runtime

gantt.sort({ key: ColumnKey.Progress, direction: 'desc' })
gantt.toggleSort(ColumnKey.Name)                     // header-click cycle: asc → desc → none
gantt.toggleSort(ColumnKey.StartTime, { append: true })  // Shift+click: add a secondary key
gantt.getSort()                                      // current criteria
gantt.clearSort()                                    // back to natural order

Clicking a sortable column header cycles its sort; Shift+click adds it as an extra key. Every change emits a sortChange event.

Making a custom column sortable

Built-in value columns are sortable out of the box (all except Wbs). A custom column becomes sortable when you supply an accessor or a comparator:

columnConfig: [
  { key: 'name', title: 'Task', minWidth: '180px' },
  {
    key: 'priority',
    title: 'Priority',
    accessor: (task) => task.priority,               // comparable value
    comparator: (a, b) => a.priority - b.priority,   // optional custom ordering
  },
]

Filtering

Filtering is view-only: it changes which rows render, never the tree, WBS, or task data. A task is kept when it matches or has a matching descendant, so ancestors of matches stay visible for context. ApexGantt offers two filter surfaces plus a programmatic API.

Quick filter

A toolbar search box that matches task string fields as the user types.

const gantt = new ApexGantt(el, {
  series: tasks,
  enableQuickFilter: true,
  quickFilter: { placeholder: 'Find a task', fields: ['name'], caseSensitive: false },
})

fields defaults to ['name']; add more string fields to widen the search.

Advanced filter builder

A "Filter" toolbar button (with an active-rule count badge) opens a popover for composing field / operator / value conditions combined with All (AND) or Any (OR). Operators adapt to the column's value type.

const gantt = new ApexGantt(el, {
  series: tasks,
  enableFilterBuilder: true,
  filterRules: {
    match: 'all',
    rules: [{ field: 'progress', operator: 'lt', value: 100 }],
  },
})

Programmatic filtering

gantt.filter((task) => task.progress < 100)          // predicate filter
gantt.setFilterRules({                               // structured filter
  match: 'any',
  rules: [
    { field: 'progress', operator: 'lt', value: 100 },
    { field: 'name', operator: 'contains', value: 'design' },
  ],
})
gantt.getFilterRules()                               // active rule set, or null
gantt.clearFilter()                                  // show every row again

All filter entry points emit a filterChange event.

Filter operators

A structured FilterRule uses one of these operators. Which are valid depends on the column's value type; isEmpty / notEmpty apply to any type and ignore value.

OperatorApplies toMeaning
contains / notContainsTextSubstring match
equals / notEqualsAnyExact match
startsWith / endsWithTextPrefix / suffix match
gt / gte / lt / lteNumberGreater / less than (or equal)
before / after / onDateDate comparison (value is YYYY-MM-DD)
isEmpty / notEmptyAnyValue is (not) empty

Events

EventDetail
sortChange{ criteria: { key, direction }[], timestamp }
filterChange{ active, visibleCount, timestamp }

React example

import { ApexGanttChart } from 'react-apexgantt'
import { ColumnKey } from 'apexgantt'
import type { GanttUserOptions } from 'react-apexgantt'

const options: Omit<GanttUserOptions, 'series'> = {
  sortBy: [{ key: ColumnKey.Progress, direction: 'desc' }],
  enableQuickFilter: true,
  enableFilterBuilder: true,
  filterRules: {
    match: 'all',
    rules: [{ field: 'progress', operator: 'lt', value: 100 }],
  },
}

export default function SortFilterGantt() {
  return <ApexGanttChart tasks={tasks} options={options} height="500px" />
}