import { Gantt } from "@elabs-ai/components-charts";npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-chartsPaste it into Claude Code, Cursor, Codex or any other coding agent. Text in [brackets] is yours to fill in.
Add the brand-ui Gantt chart (from @elabs-ai/components-charts) to this project. 1. Read https://elabs-ai.com/llms.txt first: it maps every package and the rules. If you can use MCP servers, connect https://elabs-ai.com/mcp and use its search, docs and tokens tools. If not, run the same lookups in the terminal: `npx -y @elabs-ai/components-cli search "<what you need>"` and `npx -y @elabs-ai/components-cli docs <Component>`. 2. Look Gantt up before writing code: `npx -y @elabs-ai/components-cli docs Gantt` prints its real props, variants, what it pairs with and what to avoid. 3. If @elabs-ai/components-charts is not installed yet: `pnpm add @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts` (or `npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts`). If this is the first brand-ui package in the project, wire it once: import `@elabs-ai/components-tokens/styles.css` plus the `themes/light.css` and `themes/dark.css` stylesheets in the CSS entry, add one Tailwind `@source` line per installed @elabs-ai package (Tailwind does not scan node_modules, so without it everything renders unstyled), and wrap the app root in `ThemeProvider` from `@elabs-ai/components-tokens`. 4. Use it here: [the screen or file, and what it should show] 5. Rules: use only @elabs-ai/components-* components and the semantic tokens — no raw colours, no raw font sizes, no arbitrary Tailwind values. Look up each component's real props with the docs tool before you use it; never guess a prop. 6. Done means: the typecheck passes, `npx -y @elabs-ai/components-cli audit src --strict` reports nothing, and you have opened the app and looked at every screen you touched in the light and the dark theme.
Use it for
- tasks or phases across a timeline, with dependencies between them
Avoid
- it is not really scheduled work — a dumbbell chart shows a single before and after
- Mutating task dates inside the component on drag — Gantt is emit-only; the app owns the model (D5).
- Bar labels that rely on the bar fill for contrast — check the label against the bar color in every theme.
- Rendering the grid without status="loading" while rows are still fetching — skeleton rows must hold the layout.
Works with
Used inside
Pairs with
Examples
View Mode Day
View Mode Week
View Mode Month
View Mode Quarter
With Dependencies
With Milestones
Hierarchy Expanded
Hierarchy Collapsed
Virtualized (60 tasks)
Editable
Empty
Loading
Multi Column Grid
Multi-column left grid (P1) — name stays in the accessible Tree; the data columns are an aria-hidden overlay.
Grouped Timescale
Three stacked timescale rows via an explicit `scales` array (P1).
Label Position End
Bar labels placed at the END so short bars/milestones stay legible (P1).
Label Hidden
Bar labels hidden — relies on the task grid / tooltip / aria-label (P1).
Weekend Highlight
Weekend highlight bands via `highlightTime` (P1) — token-backed classes only.
Drag To Edit
Pointer drag (P1, emit-only) — drag a bar body to move, drag the edges to resize; selecting a bar reveals the link handle (drag onto another bar to emit `onDependencyCreate`). The play test performs a real move drag.
Baseline Track
Planned-vs-actual baseline track under each bar (P2).
Gap Bands
Idle-time bands (P2, #221) — a hatched fill spanning a row's `gaps` entries, reusing the ADR 0011 series-pattern mechanism UNCONDITIONALLY (not gated behind high decoration): the meaning ("idle") must not rest on colour alone (WCAG 1.4.1), so the hatch shape is always the second channel. Hover the band, or inspect its `aria-label`, for the accessible name — the caller's `label` when given, else a generated description.
Annotations
Vertical annotation markers (P2) — themed lines + label chips.
Custom Task Types
Custom task types (P2) — color + shape per type.
Inside Label Contrast
Inside-label contrast target (#259) — bars on the lowest-contrast fills (destructive, warning, chart-3) plus a consumer-supplied `taskTypes` color, so the on-bar label pill can be checked across every theme (light/dark) on the fills most likely to fail.
Custom Bar Render
Custom bar renderer (P2) — escape hatch; consumer owns the leaf-bar visual.
Localized
Localized dates (P2) — `locale` drives the default Intl formatting.
Zoomable
Continuous zoom (P2) — Ctrl/⌘ + wheel emits a controlled `cellWidth`.
Sortable Columns
Sortable + resizable columns (P2) — emit-only; the consumer sorts/sizes.
Full Featured
Everything together — grid + grouped timescale + weekend bands + editing.
Agent Run Trace
Sub-day time units (#360) — the same `Gantt` over a **12-second** agent run. `defaultViewMode="auto"` derives the finest readable unit from the data's own span (here: seconds); the toolbar offers `Millisecond / Second / Minute`, and Ctrl/⌘ + scroll zooms continuously. `pixelsPerDay` keeps its exact meaning — pixels per 86 400 000 ms — at every granularity.
Millisecond Trace
Sub-SECOND granularity — a 40 ms dispatch trace with millisecond ticks (`fractionalSecondDigits`). Same component, same `pixelsPerDay` semantics.
Critical Path
The critical path: the zero-float chain gets a solid destructive ring on its bars and solid links (dashed elsewhere). Here Research → Design (c) → Development → Testing → Launch is critical; Prototype (b) has float.
Progress Line
The progress line at a status date (here day 20): bends left on tasks behind plan, right on tasks ahead, stays straight on work not started.
Time Ranges
Highlighted spans behind the bars — a sprint, a freeze, a holiday — with sticky labels.
Rollups
Collapsed phases keep their child milestones and bars as small marks on the summary row.
Zoom Controls
Zoom in / out / fit beside the scale presets. A step keeps the date at the pane centre where it is and morphs every bar, marker and tick to its new place; Ctrl/⌘ + wheel zooms around the pointer. Switching a scale preset is the same animated step.
Scroll To Task
Select a task, zoom until its bar leaves the pane: a round button at the pane edge scrolls it back into view.
API
Gantt
| Prop | Type | Description |
|---|---|---|
messages | ChartMessages | messages group (RM-187): this chart's own words, keyed by the ui catalogue's `charts.*` message keys. A key set here wins over the `LocaleProvider`; every other key reads the catalogue as before. |
tasksrequired | GanttTask[] | Task data. |
rowHeight | number | Row height override (px). Defaults to density-derived value. |
viewMode | GanttTimeUnit | Controlled tick granularity. Accepts any {@link GanttTimeUnit}. |
defaultViewMode | GanttTimeUnit | "auto" | Initial tick granularity. Default `"week"`. Pass `"auto"` to derive the finest readable unit from the data's own span (see {@link pickGanttTimeUnit}) — the default stays `"week"` so no existing surface changes granularity (#360). |
onViewModeChange | (mode: GanttTimeUnit) => void | Emitted when the granularity changes. **Migration (#360):** the parameter widened from `GanttViewMode` to {@link GanttTimeUnit}. Under `strictFunctionTypes` a handler *explicitly* annotated `(mode: GanttViewMode) => void` no longer assigns — annotate it `GanttTimeUnit`, or drop the annotation (the common inferred form `onViewModeChange={(mode) => …}` is unaffected). Runtime behaviour is unchanged: without `viewModes` the toolbar still only emits the four calendar presets. |
viewModes | GanttTimeUnit[] | Units offered by the toolbar's segmented control. Default `["day", "week", "month", "quarter"]`. |
selectedId | string | |
defaultSelectedId | string | |
onSelect | (id: string | undefined) => void | |
expandedIds | string[] | |
defaultExpandedIds | string[] | |
onExpandedChange | (ids: string[]) => void | |
onTaskMove | (id: string, start: Date, end: Date) => void | |
onTaskResize | (id: string, edge: "start" | "end", date: Date) => void | |
onDependencyCreate | (from: string, to: string) => void | |
pointerDrag | boolean | Enable pointer drag (move / resize-edge / create-link), in addition to the always-available keyboard editing. Drag fires the SAME emit-only `onTaskMove` / `onTaskResize` / `onDependencyCreate` — the task model is never mutated (D5). Defaults to `true` when any of those callbacks is provided; pass `false` to force keyboard-only. |
columns | GanttColumn[] | Left-pane columns. The first column hosts the task name + tree affordances. |
scales | GanttScale[] | Stacked timescale rows. Overrides the `viewMode`-derived default. |
labelPosition | GanttLabelPosition | Bar-label placement. Default `"inside"`. |
highlightTime | GanttHighlightTime | Returns a semantic `bg-*` class for a vertical band at `date`, else undefined. |
markers | GanttMarker[] | Vertical annotation markers (themed line + optional label at a date). |
timeRanges | GanttTimeRange[] | Highlighted time spans behind the bars (a sprint, a freeze, a holiday) with a label chip. |
showCriticalPath | boolean | Mark the critical path: the dependency chain with zero float (classic CPM over finish-to-start links, durations = the tasks' spans). Critical bars get a solid `destructive` ring and "critical" in their accessible name; critical links draw solid. |
progressLine | boolean | Date | string | number | The project progress line: a vertical line at the status date that bends left to the point each task has reached (behind) or right (ahead). `true` = today. |
rollups | boolean | Roll child milestones and bars up onto a collapsed summary row as small marks, so a folded phase still shows what it contains. Default `false`. |
renderBar | (task: ResolvedTask) => ReactNode | Custom LEAF-bar renderer (escape hatch). Your node fills the bar rect and is `aria-hidden`; the button shell (selection, keyboard editing, pointer drag, tooltip, baseline) is preserved. Summary brackets and milestones keep their built-in rendering. Omit for the default type-driven rendering. |
taskTypes | Record<string, GanttTaskType> | Custom task types (color/shape) selected per task via `GanttTask.type`. |
locale | string | BCP-47 locale for the default date formatting (passed to `Intl`). |
formatDate | GanttFormatDate | Override date formatting entirely (P2). Defaults to `Intl` + `locale`. |
pixelsPerDay | number | Controlled pixels-per-day (continuous zoom). Overrides the view-mode preset — so a scale switch in the toolbar can only change the density through `onPixelsPerDayChange`, which then receives the new scale's preset. |
defaultPixelsPerDay | number | Initial pixels-per-day for uncontrolled zoom (enables Ctrl/⌘ + wheel out of the box). A seed for the FIRST view only: picking another scale in the toolbar re-derives the density from that scale's preset (Day / Week / Month / Quarter are zoom levels). |
onPixelsPerDayChange | (pixelsPerDay: number) => void | Emits the proposed pixels-per-day: on Ctrl/⌘ + wheel zoom, and on a toolbar scale switch (the new scale's preset, floored at "whole domain fits the pane"). |
zoomBounds | { minPixelsPerDay?: number; maxPixelsPerDay?: number } | Override the span-derived zoom clamp (see {@link computeGanttZoomBounds}). Both bounds are in pixels-per-day, at every granularity (#360). |
sort | GanttSort[] | Controlled sort descriptors (drive the header sort indicators). |
onSortChange | (sort: GanttSort[]) => void | Header click on a `sortable` column emits the next sort state. |
onColumnResize | (columnId: string, width: number) => void | Header-edge drag on a `resizable` column emits the proposed width. |
labelColumnWidth | number | Left pane width (px). Default 240. Ignored when `columns` is set (widths sum). |
status | ChartStatus | chart-state group (RM-194). `"loading"` renders a built-in shimmer loading state (Skeleton rows in both panes) instead of the task tree and canvas, until the tasks are `"ready"`. Use while data is in flight. Default `"ready"`. |
empty | ChartEmptyState | chart-state group (RM-194): what shows when `tasks` is empty. `message` replaces the default sentence, `title` is printed above it and `action` below it. Unset keys keep the default: no title, the `charts.gantt.noTasksToDisplay` message, no action. |
loading | boolean | When true, renders a built-in shimmer loading state (Skeleton rows in both panes) instead of the task tree and canvas. Use while data is in flight. @deprecated Since 6.0.0, use `status` — `loading={true}` is `status="loading"`, `loading={false}` is `status="ready"`. Removed in 7.0.0. |
children | ReactNode |
Theming
The tokens each state resolves to. Change the token and every theme follows.
| State | Token |
|---|---|
| status | status="loading" → skeleton rows + overlay spinner; "ready" → the grid |