Skip to main content
The timeline is the chart area to the right of the grid. Its header rows (scales) and horizontal granularity are controlled by a handful of props on <Gantt>.

The scales prop

scales is an array of scale row definitions, ordered from largest time unit (top) to smallest (bottom). Each entry renders as one header row above the task bars.
<Gantt
  tasks={tasks}
  links={links}
  scales={[
    { unit: 'month', step: 1, format: '%F %Y' },
    { unit: 'day',   step: 1, format: '%j' },
  ]}
/>
The default scales show a month row followed by a day row.

Scale object fields

unit
string
required
Time unit for this row. Built-in values: 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'. Custom units can be registered with registerScaleUnit.
step
number
default:"1"
How many units each cell spans. For example { unit: 'day', step: 7 } gives one cell per week without using the 'week' unit.
format
string | ((start: Date, end: Date) => string)
Label displayed in each cell. Accepts a strftime-style format string or a function that receives the cell’s start and end dates and returns a string.Common format tokens:
TokenOutput
%Y4-digit year
%FFull month name
%MShort month name
%jDay of month
%HHour (24h)
%iMinutes
%WISO week number
%QQuarter number
%wWeek number (locale)
css
(date: Date) => string
Function that returns a CSS class name for each cell. Use it to highlight weekends or other special periods.
const dayStyle = (date) =>
  date.getDay() === 0 || date.getDay() === 6 ? 'sday' : '';

scales={[{ unit: 'day', step: 1, format: '%j', css: dayStyle }]}

Common scale configurations

const scales = [
  { unit: 'month', step: 1, format: '%F %Y' },
  { unit: 'day',   step: 1, format: '%j' },
];

Cell sizing

cellWidth
number
default:"100"
Width in pixels of the smallest-unit cell. All timeline columns are this wide. Increase it to make bars less compressed.
cellHeight
number
default:"38"
Height in pixels of each task row, including the task bar.
scaleHeight
number
default:"36"
Height in pixels of each scale header row. Applies to every scale row.

Fixed date range

By default the timeline adjusts its start and end to fit the tasks (autoScale: true). You can pin the visible range with start and end.
<Gantt
  tasks={tasks}
  links={links}
  scales={scales}
  start={new Date(2026, 3, 1)}   // April 1 2026
  end={new Date(2026, 4, 12)}    // May 12 2026
/>
start
Date
default:"null"
Left edge of the visible timeline. When null the timeline starts before the earliest task.
end
Date
default:"null"
Right edge of the visible timeline. When null the timeline ends after the latest task.
autoScale
boolean
default:"true"
When true the timeline expands automatically to always fit all tasks. Set to false when providing a fixed start / end.

lengthUnit

lengthUnit controls the granularity of the smallest cell on the timeline. It affects how far a task bar moves when you drag it one cell, and how the scroll position snaps.
<Gantt
  tasks={tasks}
  links={links}
  scales={[
    { unit: 'day',  step: 1, format: '%M %j' },
    { unit: 'hour', step: 1, format: '%H:%i' },
  ]}
  lengthUnit="minute"   // snaps to the minute
  durationUnit="hour"
/>
lengthUnit
'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter'
default:"'day'"
The unit that one cell column represents on the timeline. Must match (or be finer than) the smallest unit in your scales array.

Zoom

The zoom prop enables interactive zooming. Hold Ctrl and scroll the mouse wheel over the chart to zoom in and out.
Pass zoom={true} to use the built-in zoom levels.
<Gantt tasks={tasks} links={links} zoom />
The built-in levels cycle through year → quarter/month → month/week → month/day → day/hour scales.

Zoom level object fields

scales
IScale[]
required
The scale rows to display at this zoom level.
minCellWidth
number
The narrowest cell width this level will allow before zooming in to the next finer level.
maxCellWidth
number
The widest cell width this level will allow before zooming out to the next coarser level.
The level field on the zoom config object sets the initial level index. Levels are 0-based from the coarsest to the finest.

Custom scale units

Register a custom unit name with registerScaleUnit before rendering the component.
import { registerScaleUnit, Gantt } from '@svar-ui/react-gantt';
import { startOfMonth, endOfMonth, isSameMonth, addMonths, addDays } from 'date-fns';

registerScaleUnit('sprint', {
  // Returns the start of the sprint that contains `date`
  start: (date) => {
    const s = startOfMonth(date);
    if (date.getDate() >= 16) s.setDate(16);
    return s;
  },
  // Returns the end of the sprint that contains `date`
  end: (date) => {
    const e = endOfMonth(date);
    if (date.getDate() < 16) e.setDate(15);
    return e;
  },
  // Returns true when two dates fall within the same sprint cell
  isSame: (a, b) => {
    if (!isSameMonth(a, b)) return false;
    return (a.getDate() < 16) === (b.getDate() < 16);
  },
  // Advances `date` by `amount` sprints
  add: (date, amount) => addDays(addMonths(date, Math.floor(amount / 2)), (amount % 2) * 16),
});

// Then use 'sprint' as any other unit
const scales = [
  { unit: 'month',  step: 1, format: '%F %Y' },
  { unit: 'sprint', step: 1, format: (d) => `Sprint ${d.getDate() < 16 ? 'A' : 'B'}` },
  { unit: 'day',    step: 1, format: '%j' },
];
Call registerScaleUnit once at module level or inside a ref-guard to avoid re-registering on every render.

Props reference

PropTypeDefaultDescription
scalesIScale[]month + dayHeader row definitions
zoomboolean | IZoomConfigfalseEnables Ctrl+scroll zoom
lengthUnitstring'day'Smallest timeline cell unit
durationUnitstring'day'Unit for numeric duration values
cellWidthnumber100Width of each timeline cell in px
cellHeightnumber38Height of each task row in px
scaleHeightnumber36Height of each scale header row in px
startDate | nullnullFixed left boundary of the timeline
endDate | nullnullFixed right boundary of the timeline
autoScalebooleantrueAuto-expand timeline to fit all tasks

Build docs developers (and LLMs) love