Skip to content

Gantt ​

Project-scheduling chart component (data family): a WBS row tree (parent summary bars span the union of their children's time) against a horizontal time axis, with three bar forms (task / milestone / summary) plus progress fill; dependency links (FS/SS/FF/SF, drawn on a single SVG overlay); a drag trio (drag to reschedule, edge handles to resize, in-bar handle to change progress — written back once on pointerup with events); six time scales (hour/day/week/month/quarter/year) with a two-tier header; today line and weekend/holiday column highlights; row virtualization for tens of thousands of tasks; three readonly levels plus per-task disabling. The data contract is a flat parent pointer list (nested children input is flattened automatically).

Basic Usage ​

WBS row tree + dependency links + milestones + progress (tasks JSON; flat parent / nested children both accepted)

  • Parent tasks render summary bars (time = union of children, progress = duration-weighted average); the row toggle collapses/expands children; the expanded set is written back to the expanded attribute (JSON array) with oas-expand-change; collapsed sub-rows hide together with their dependency links (links follow row visibility, they do not reroute to the summary bar);
  • Milestones render as diamonds: an explicit type: "milestone" takes precedence (a task renders as a milestone even when it carries end; the end is ignored with a one-time console.warn about the data conflict); tasks without end also infer as milestones; a task with children always renders as a summary bar (children carry the aggregation semantics, so form and aggregation must agree; a one-time console.warn about the data conflict fires only when type: "milestone" is also declared explicitly); a start after end (reversed dates) is swapped automatically at the sanitize layer with a one-time console.warn (no 2px ghost bar);
  • dependencies declare links (type defaults to fs; fs/ss/ff/sf supported) drawn as polylines with arrowheads on a single SVG canvas;
  • Hovering a bar shows a tooltip (name + range + progress); template[slot="tooltip"] overrides the content (bind points [data-task-name] / [data-task-range] / [data-task-progress]).

Time Scales (scale) ​

Six scales: hour / day (default) / week / month / quarter / year (two-tier header: merged major tier + per-unit minor tier)

Changing scale re-lays the time axis (column width adapts per tier, with a floor that keeps labels legible) and dispatches oas-scale-change; invalid values fall back to day. When the container squeezes columns too narrow for labels, minor ticks are thinned by N (grid lines kept, some texts hidden — e.g. every 2nd day on a narrow day axis) so day/month numbers never collide. Dragging snaps to the current scale unit (snap="false" disables snapping and shifts by pixel ratio, preserving time precision).

Drag Trio ​

Drag body to reschedule / edge handles to resize / dot handle for progress (written back once on pointerup; Esc or pointercancel cancels with zero events)

  • Drag the body = move as a whole (duration kept); drag edge handles = change start/end (cannot cross the opposite side); drag the in-bar dot = change progress;
  • Written back on pointerup with oas-task-change (detail: { id, task, oldStart, oldEnd, start, end }) / oas-progress-change (detail: { id, task, progress }) plus oas-tasks-change (full list); releasing without movement dispatches nothing;
  • Esc (or pointercancel) while dragging cancels → visual rollback, zero events; rewriting tasks externally mid-drag aborts the drag (external data wins);
  • With a bar focused, Shift + ←/→ reschedules by one unit (mirrored in RTL).

Readonly Levels + Per-task Disable ​

readonly (all) / dates-readonly (no rescheduling) / progress-readonly (no progress drag); readonly states render no drag handles (visual = semantics)

readonly: whole chart read-only
dates-readonly: dates locked, progress still draggable
progress-readonly: progress locked, dates still draggable

disabled: true in task data disables that single bar (others unaffected).

Today Line & Weekend/Holiday Highlights ​

Today line (show-today on by default) + weekend column highlights (weekends on by default) + holidays (demo range dynamically covers today)

Today line off / weekend highlights off / holiday highlights (holidays JSON)

The today line is decorative (aria-hidden) and renders only when today falls inside the axis range; weekend/holiday column tints apply on the day/hour tiers.

Row Virtualization (10k-scale tasks) ​

height + row-height enable viewport windowing (300 rows demoed; only the visible window + buffer renders)

Methods: scrollToTask row 250

Methods: scrollToTask(id) to bring a task row into view, scrollToDate(date) / scrollToToday() for horizontal positioning, updateTask(id, patch) for single-task incremental updates (sanitized, dispatches oas-tasks-change).

Controlled Expansion / Labels & Snapping / Localization ​

expanded as a controlled set (JSON array = expanded set; explicit [] collapses all) + label-position (default none, since the row-name column already shows names; inside / right must be opted in)

snap=false (pixel-ratio shift keeps time precision) + locale / first-day-of-week

template[slot="task"] overrides in-bar label content ([data-task-name] binding; labels are not rendered by default with label-position="none", so the template takes effect only after opting in); each rendered bar dispatches oas-task-render (detail: { task, element }) so hosts can rewrite its DOM.

API ​

oas-gantt ​

Attributes ​

AttributeDescriptionTypeDefault
dates-readonlyNo rescheduling/resizing (progress still draggable)boolean—
expandedExpanded set (JSON array, controlled): defaults to fully expanded when absent; explicit [] collapses all; written back on togglestring—
first-day-of-weekWeek start day (0-6); defaults to locale derivation (used for week-tier alignment)string—
heightComponent height in px (default 320)string320
holidaysHoliday list (JSON ["YYYY-MM-DD",…]): matching columns highlighted (takes precedence over weekend tint)string—
label-positionBar label position: inside / right / left; default none (the row-name column already shows the name, so the bar does not repeat it); invalid values fall back to nonestring—
localeLocalization (overrides config-provider injection and the global locale)string—
progress-readonlyNo progress dragging (dates still draggable)boolean—
readonlyWhole chart read-only (no rescheduling/progress, drag handles not rendered)boolean—
row-heightRow height in px (default 36, minimum 20)string36
scaleTime scale: hour / day (default) / week / month / quarter / year; invalid values fall back to daystring—
show-todayToday line (on by default; false to disable)string—
snapSnap drags to the current scale unit (on by default; false shifts by pixel ratio and keeps time precision)string—
tasksGantt tasks (JSON): [{ id?, name, start, end?, type?, progress?, parent?, children?, dependencies?, color?, disabled?, expanded? }] — flat parent pointers are the primary contract; nested children are flattened automatically; explicit type:"milestone" takes precedence (rendered as milestone even with end, which is ignored) but a task with children is always a summary; no end also infers milestone; start/end are swapped automatically when start is after endGanttTask[][]
weekendsWeekend column highlights (on by default; applies on day/hour tiers; false to disable)string—

Property (JS property; see each row for attribute reflection) ​

PropertyDescriptionTypeDefault
tasksGantt tasks (GanttTask[]): el.tasks reads (copy; nested input already flattened to parent pointers); el.tasks = [...] writes (syncs the tasks attribute + re-renders + dispatches oas-tasks-change)GanttTask[][]

Events ​

EventDescription
oas-expand-changeDispatched on row tree collapse/expand, detail:
oas-progress-changeDispatched when a progress handle drag settles, detail:
oas-scale-changeDispatched when the scale attribute changes, detail: { scale }; not dispatched on initial absorption
oas-task-changeDispatched when a drag/resize/keyboard reschedule settles (pointerup), detail: { id, task, oldStart, oldEnd, start, end }; not dispatched on zero movement
oas-task-clickDispatched on task bar/milestone click, detail:
oas-task-dblclickDispatched on task bar double-click, detail: { id, task } — hosts attach an edit form
oas-task-renderDispatched after each task bar renders, detail: { task, element } — hosts may rewrite bar DOM
oas-tasks-changeDispatched on task data change (programmatic tasks write / updateTask / drag write-back), detail:

Slots ​

NameDescription
template[slot="empty"]Empty-state content (defaults to "No tasks")
template[slot="task"]Task bar label template (cloned into the bar; [data-task-name] nodes get the task name)
template[slot="tooltip"]Hover tooltip template ([data-task-name] / [data-task-range] / [data-task-progress] bind points)

CSS Variables ​

CSS VariableDefault
--oas-gantt-bar-bgcolor-mix(in srgb, var(--oas-gantt-bar-color, var(--oas-color-primary)) 22%, transparent)
--oas-gantt-bar-height22px
--oas-gantt-bar-progress-bgvar(--oas-gantt-bar-color, var(--oas-color-primary))
--oas-gantt-grid-line-colorvar(--oas-color-border)
--oas-gantt-header-bgvar(--oas-color-bg)
--oas-gantt-header-height44px
--oas-gantt-height320px
--oas-gantt-holiday-bgcolor-mix(in srgb, var(--oas-color-warning) 12%, transparent)
--oas-gantt-link-colorvar(--oas-color-primary)
--oas-gantt-list-width220px
--oas-gantt-milestone-colorvar(--oas-color-warning)
--oas-gantt-row-height36px
--oas-gantt-summary-bgvar(--oas-color-text-secondary-strong)
--oas-gantt-today-colorvar(--oas-color-danger)
--oas-gantt-weekend-bgcolor-mix(in srgb, var(--oas-color-bg-hover) 60%, transparent)

Released under the MIT OR Apache-2.0 License.