@jaeungkim/gantt-chart

Grouping types

`GanttGroupBy`, `GanttRow`, `GanttRowGroup`

GanttGroupBy is the type of the groupBy prop. GanttRow and GanttRowGroup describe the row model the chart builds from your tasks — one entry per rendered row, group header rows included. All three come from the package root.

import type { GanttGroupBy, GanttRow, GanttRowGroup } from '@jaeungkim/gantt-chart';

For what grouping does and how lanes pack, see Grouping and swimlanes.

GanttGroupBy

/**
 * How rows are grouped into swimlanes
 *
 * A string reads that field off the task; a function returns the group value
 * itself, which doubles as the header label. Anything empty, null or undefined
 * lands in the "Ungrouped" bucket.
 */
export type GanttGroupBy =
  | string
  | ((task: TaskTransformed) => string | null | undefined);
FormMeaning
stringA field name, read off the task with an unchecked index. Any field of TaskTransformed works, not only the ones Task declares. A name no task carries yields undefined for every task, so every task lands in one Ungrouped group.
(task: TaskTransformed) => string | null | undefinedReturns the group value. The value is also the header label.

Non-string return values are passed through String(value). Only null, undefined and "" produce the Ungrouped bucket — 0 becomes the group "0" and false becomes the group "false".

The accessor receives a TaskTransformed, not the Task you passed in, so it also sees depth, order, isSummary, barLeft, barWidth, and the scheduling fields the chart adds. See Task.

GanttRowGroup

export interface GanttRowGroup {
  /** The raw value `groupBy` produced ("" for the ungrouped bucket) */
  key: string;
  /** What the header shows */
  label: string;
  /** How many tasks the group holds (rows can be fewer - lanes share a row) */
  count: number;
}
FieldTypeNotes
keystringThe stringified groupBy value. "" for the Ungrouped bucket.
labelstringEqual to key, except for the Ungrouped bucket, where it is the ungroupedLabel prop — "Ungrouped" when the prop is not set.
countnumberTasks in the group, counted among the tasks the chart currently renders. Not a row count: lane-mates share a row.

GanttRow

/**
 * One rendered row
 *
 * Normally one task, several when they share a `lane`, none when the row is a
 * group header. The tree numbers (`level`/`posinset`/`setsize`) are the ARIA
 * values for the row, so the render never has to work them out again.
 */
export interface GanttRow {
  /** Stable key - the group id for a header, otherwise the ids on the row */
  id: string;
  tasks: TaskTransformed[];
  /** Indentation level, 0-based */
  depth: number;
  /** `aria-level`, 1-based */
  level: number;
  /** `aria-posinset` among the rows that share a parent */
  posinset: number;
  /** `aria-setsize` for that same set */
  setsize: number;
  /** Set only on a group header row */
  group?: GanttRowGroup;
}
FieldTypeNotes
idstringSee Row ids.
tasksTaskTransformed[]Empty on a group header row. One entry on a normal row, several when tasks share a lane.
depthnumber0-based. Group headers are 0; every task row inside a group sits at its task depth + 1.
levelnumberaria-level. Always depth + 1.
posinsetnumberaria-posinset among the rows sharing this row's parent. A row's parent is the nearest row above it one depth shallower.
setsizenumberaria-setsize for that same set. Counts visible rows only.
groupGanttRowGroup | undefinedPresent only on a group header row. Its absence is how a task row is told apart from a header.

Row ids

Row kindidExample
Group header`group:${key}`groupBy yields "Dev""group:Dev"
Ungrouped header"group:"The key is "", so nothing follows the colon. The label plays no part — "group:Ungrouped" matches nothing.
Task rowthe task id"a"
Lane rowthe packed task ids joined with "+""a+b"

Group header ids go in the same flat collapsedIds / defaultCollapsedIds array as task ids. Collapsing the Ungrouped group means collapsedIds={['group:']}.

Not exported

src/utils/grouping.ts also holds buildGanttRows, packLanes, groupRowId, GROUP_ROW_PREFIX, DEFAULT_UNGROUPED_LABEL and BuildGanttRowsOptions. None of them are re-exported from the package, and none are part of the headless core — grouping runs on the render side. Build a group id as the literal string `group:${key}` rather than importing a helper for it.

Notes

  • No prop or callback hands you a GanttRow. The two row types are exported so host code can name the shape the chart works in — for reading TaskTransformed.order, or for matching a collapsedIds entry.
  • order on a TaskTransformed is the 1-based row number, assigned after grouping. Group header rows consume numbers, and every task on a lane row reports the same order.
  • count is taken before a collapse is applied to the group itself, so a collapsed group still shows its full number. It is taken after collapsed subtrees are removed, so collapsing a summary row inside the group lowers it.
  • ungroupedLabel="" produces an empty header label. The "Ungrouped" default only fills in for undefined.
  • Group headers are always at depth: 0. There are no nested groups: groupBy takes one value, not a list.

Next: Task for TaskTransformed, or GanttProps for groupBy and ungroupedLabel in the prop index.

On this page