<bmx-gantt>
A project plan: the task list on the left, the timeline on the right, and the links between the tasks drawn across it.
21 properties · 6 events · 12 methods · 30 parts
Example
bmxTaskChange and bmxLinkChange
carry the whole list as it would be; call preventDefault() to refuse one, or set
apply-changes="false" and assign the lists yourself. canChange refuses a drag while it
is still in the reader's hand.
2, 3SS+1 — so nothing the
pointer can do needs a pointer.
Show markup
<bmx-gantt
label="Office move"
project-start="2026-03-02"
holidays="2026-04-03,2026-04-06"
editable
show-baselines
tasks='[
{"id":"p","name":"Planning"},
{"id":"p1","parentId":"p","name":"Survey the new site","duration":3,"progress":100},
{"id":"p2","parentId":"p","name":"Agree the floor plan","duration":4,"progress":60,"baselineStart":"2026-03-04","baselineFinish":"2026-03-09"},
{"id":"p3","parentId":"p","name":"Plan signed off","milestone":true},
{"id":"f","name":"Fit-out"},
{"id":"f1","parentId":"f","name":"Network cabling","duration":6,"progress":20},
{"id":"f2","parentId":"f","name":"Furniture delivery","duration":2},
{"id":"f3","parentId":"f","name":"Meeting rooms AV","duration":5},
{"id":"m","name":"Move"},
{"id":"m1","parentId":"m","name":"Pack","duration":3},
{"id":"m2","parentId":"m","name":"Move day","duration":1},
{"id":"go","name":"Open for business","milestone":true}
]'
links='[
{"from":"p1","to":"p2"},{"from":"p2","to":"p3"},{"from":"p3","to":"f1"},
{"from":"p3","to":"f2","lag":2},{"from":"f1","to":"f3","type":"SS","lag":2},
{"from":"f","to":"m"},{"from":"m1","to":"m2"},{"from":"m2","to":"go"}
]'
></bmx-gantt>
<div class="row" style="margin-block-start: 1rem">
<span class="note">
<strong>The dates are worked out, not typed.</strong> Each task has a duration and links; the chart schedules
them against the working calendar — weekends and the two holidays here — and draws the tasks with no
room to slip as the critical path. Drag a bar, its end or its progress grip, or draw a link from the dot at a
bar's end to another bar, and everything that depends on it moves with it.
</span>
</div>
<div class="row" style="margin-block-start: 1rem">
<span class="note">
<strong>Every edit is a cancelable event.</strong> <code>bmxTaskChange</code> and <code>bmxLinkChange</code>
carry the whole list as it would be; call <code>preventDefault()</code> to refuse one, or set
<code>apply-changes="false"</code> and assign the lists yourself. <code>canChange</code> refuses a drag while it
is still in the reader's hand.
</span>
</div>
<div class="row" style="margin-block-start: 1rem">
<span class="note">
<strong>Tab into the task list once, then use the keyboard.</strong> The arrows move between rows,
<kbd>→</kbd> and <kbd>←</kbd> open and close a summary, <kbd>F2</kbd> edits a cell,
<kbd>Shift</kbd>+<kbd>→</kbd> moves a task a working day and <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>→</kbd>
lengthens it. Links are typed in the Predecessors column — <code>2, 3SS+1</code> — so nothing the
pointer can do needs a pointer.
</span>
</div>
<bmx-gantt
label="Office move"
project-start="2026-03-02"
tasks='[{"id":"1","name":"Survey","duration":3},
{"id":"2","name":"Fit-out","duration":10}]'
links='[{"from":"1","to":"2"}]'
></bmx-gantt>
THE DATES ARE WORKED OUT, NOT TYPED
A task has a duration and links; where it falls follows from those and from
the working calendar - weekends, holidays - by the critical-path method.
Move one task and everything that depends on it moves with it; the tasks
with no room to slip are drawn as the critical path. A start on a task is
the earliest it may begin, not a date it is stuck on, so a plan stays
consistent however it is edited. The arithmetic is shared with
bmx-pert-chart and bmx-task-board, and with the WPF and Windows Forms
editions of this chart, so the same plan gives the same dates everywhere.
A TREEGRID, WITH THE TIMELINE BESIDE IT
The task list is a real treegrid: one Tab stop, arrow keys between rows,
Right and Left to open and close a summary, F2 to edit a cell. Everything
the timeline shows is also said in the row - dates, length, progress, float
and whether the task is critical - because a bar is a picture and a picture
cannot be read aloud. With editable set, a focused task moves a working day
at a time with Shift and the arrows and changes length with Ctrl and Shift,
and its links are typed in the Predecessors column (2, 3SS+1), so nothing
the pointer can do needs a pointer.
THE PAGE OWNS THE PLAN
Every edit is announced with bmxTaskChange or bmxLinkChange before it is
applied, carrying the whole list as it would be. Call preventDefault() to
refuse it, or set apply-changes="false" to apply nothing and assign the
lists yourself; canChange lets a rule refuse a drag while it is still in
the reader's hand.
LARGE PLANS
Only the rows and the header ticks in view are rendered, so ten thousand tasks scroll as smoothly as ten.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
applyChanges |
apply-changes |
boolean |
true |
Whether an edit is applied by the chart itself. On by default, so a plain page works with no script; turn it off to own the lists entirely. |
canChange |
property only | (detail: BmxGanttTaskChangeDetail) => boolean |
— | Whether a change may be made, asked while a drag moves and before any edit is applied. A function, so it is set from script. js gantt.canChange = ({ edits }) => edits.every(e => !e.edit.start?.endsWith('-25')); |
columns |
columns |
(BmxGanttColumn | BmxGanttColumnKey)[] | string |
[...DEFAULT_COLUMNS] |
The task-list columns, in order: columns="wbs,name,start,duration", or objects with a label and width from script. |
editable |
editable |
boolean |
false |
Lets the reader drag bars, draw links and edit cells. |
firstDayOfWeek |
first-day-of-week |
number |
1 |
The first day of the week in the headers, 0 for Sunday. |
gridWidth |
grid-width |
number |
460 |
Width of the task list in pixels. The reader can drag the divider. |
holidays |
holidays |
string[] | string |
[] |
Dates that are not worked, YYYY-MM-DD: holidays="2026-12-25,2026-12-28". |
label |
label |
string |
— | What the plan is called. Without one it is announced as "Project plan". |
links |
links |
BmxTaskLink[] | string |
[] |
The links between tasks. |
locale |
locale |
string |
— | The locale dates are written in. Defaults to the page's. |
projectStart |
project-start |
string |
— | The first day work can happen, YYYY-MM-DD. Defaults to the earliest task start. |
rowHeight |
row-height |
number |
36 |
Row height in pixels. A layout input: the timeline and the list are placed from it. |
showBaselines |
show-baselines |
boolean |
false |
Draws each task's baseline under its bar. |
showCriticalPath |
show-critical-path |
boolean |
true |
Draws the critical path in the critical colour. |
showLinks |
show-links |
boolean |
true |
Draws the links. |
showToday |
show-today |
boolean |
true |
Draws a line at today. |
tasks |
tasks |
BmxTask[] | string |
[] |
The tasks, as a flat list with parent references. |
today |
today |
string |
— | Which day is today, YYYY-MM-DD. Defaults to the reader's date. |
toolbar |
toolbar |
boolean |
true |
Shows the zoom and "today" buttons above the chart. |
workingDays |
working-days |
number[] | string |
[1, 2, 3, 4, 5] |
Days of the week that are worked, 0 for Sunday: working-days="1,2,3,4,5". |
zoom |
zoom |
BmxGanttZoom |
'week' |
How much time the timeline shows: day, week, month, quarter or year. |
Events
| Event | Detail | Description |
|---|---|---|
bmxLinkChange |
BmxGanttLinkChangeDetail |
Links are about to change. Cancelable. |
bmxSchedule |
BmxGanttScheduleDetail |
The plan was scheduled, with anything in it that could not be used. |
bmxSelect |
BmxGanttSelectDetail |
A task was chosen. |
bmxTaskChange |
BmxGanttTaskChangeDetail |
Tasks are about to change. Cancelable. |
bmxToggle |
BmxGanttToggleDetail |
A summary task was opened or closed. |
bmxZoomChange |
{ readonly zoom: BmxGanttZoom; } |
The zoom changed. |
Methods
| Method | Signature | Description |
|---|---|---|
collapseAll |
collapseAll() => Promise<void> |
Closes every summary. |
expandAll |
expandAll() => Promise<void> |
Opens every summary. |
exportPng |
exportPng() => Promise<Blob | null> |
The whole plan as a PNG image, at twice the pixel density for print. |
exportSvg |
exportSvg() => Promise<string> |
The whole plan - every row, open or not - as a standalone SVG document. |
getSchedule |
getSchedule() => Promise<BmxSchedule> |
The plan as scheduled: dates, float, the critical path and any problems. |
print |
print() => Promise<void> |
Prints the whole plan. The chart on screen shows only what is in view, so printing the page would print a window of it; this prints every row. |
scrollToTask |
scrollToTask(id: string) => Promise<void> |
Scrolls a task into view in both panes, opening its summaries, and focuses its row. |
scrollToToday |
scrollToToday() => Promise<void> |
Scrolls the timeline to today. |
toggle |
toggle(id: string, expanded?: boolean) => Promise<void> |
Opens or closes one summary. |
zoomIn |
zoomIn() => Promise<void> |
Shows less time, in more detail. |
zoomOut |
zoomOut() => Promise<void> |
Shows more time, in less detail. |
zoomToFit |
zoomToFit() => Promise<void> |
Picks the finest zoom that shows the whole plan without scrolling sideways. |
Slots
| Slot | Description |
|---|---|
empty |
what to draw when there are no tasks. |
toolbar-end |
extra controls after the built-in zoom buttons. |
CSS shadow parts
| Part | Description |
|---|---|
bar-label |
|
baseline |
|
cell-editor |
|
chart |
|
empty |
|
frame |
|
grid |
|
grid-body |
|
grid-header |
|
link-draft |
|
link-handle |
|
link-remove |
|
links |
|
non-working |
|
plot |
|
progress |
|
progress-handle |
|
resize-handle |
|
row-band |
|
side-label |
|
splitter |
|
tick |
|
tick-major |
|
timeline-body |
|
timeline-header |
|
today |
|
toggle |
|
toolbar |
|
toolbar-button |
|
zoom-name |
CSS custom properties
| Property | Description |
|---|---|
--bmx-gantt-bar-background |
A task bar's unfinished part. |
--bmx-gantt-bar-color |
Text on a bar. |
--bmx-gantt-bar-height |
How much of the row a bar fills, as a length. |
--bmx-gantt-bar-progress |
A task bar's finished part. |
--bmx-gantt-bar-radius |
A task bar's corners. |
--bmx-gantt-baseline-color |
The baseline under a bar. |
--bmx-gantt-border |
The lines between rows, columns and header ticks. |
--bmx-gantt-critical-background |
A critical bar's unfinished part. |
--bmx-gantt-critical-progress |
A critical bar's finished part, and critical links. |
--bmx-gantt-grid-width |
Width of the task list. Written by the component from grid-width. |
--bmx-gantt-header-background |
The header rows' fill. |
--bmx-gantt-header-color |
The header text. |
--bmx-gantt-height |
How tall the chart is, header included. |
--bmx-gantt-link-color |
The links between bars. |
--bmx-gantt-non-working-background |
Weekends and holidays behind the bars. |
--bmx-gantt-row-height |
Height of a row. Written by the component from row-height. |
--bmx-gantt-row-hover |
A row under the pointer. |
--bmx-gantt-row-selected |
The chosen row, in the list and across the timeline. |
--bmx-gantt-summary-color |
A summary bar and a milestone. |
--bmx-gantt-today-color |
The line at today. @part toolbar - the zoom and "today" buttons. @part toolbar-button - one of them. @part zoom-name - the current zoom's name. @part frame - the task list, the divider and the timeline together. @part grid - the task list (role="treegrid"). @part grid-header - the list's header row. @part grid-body - the list's scrolling body. @part column-header - one heading. Also column-header-<key>. @part row - one task's row. Also row-summary, row-selected. @part cell - one cell. Also cell-<key>. @part cell-editor - the input while a cell is edited. @part toggle - the arrow that opens a summary. @part name - a task's name in the list. Also name-milestone. @part splitter - the divider between the list and the timeline. @part chart - the timeline side. @part timeline-header - the two rows of dates. @part tick - one date in them. Also tick-major, tick-minor, tick-non-working, tick-today. @part timeline-body - the scrolling timeline. @part plot - the drawing surface inside it. @part non-working - a shaded weekend or holiday. @part row-band - a row's stripe across the timeline. @part bar - one bar. Also bar-task, bar-summary, bar-milestone, bar-critical, bar-<category>. @part track - a task bar's unfinished part. @part summary-track - a summary bar. @part progress - a task bar's finished part. @part bar-label - a task's name on its bar. @part side-label - a task's name beside a bar too short to hold it. @part baseline - the baseline under a bar. @part resize-handle - the grip on a bar's end, when editable. @part progress-handle - the grip at the end of the finished part. @part link-handle - the dot a link is drawn from. @part links - the SVG layer of links. @part link - one link. Also link-critical. @part link-draft - the link being drawn. @part link-remove - the button that removes the chosen link. @part today - the line at today. @part empty - what is drawn when there are no tasks. |