Gantt
Preview: Project
Timeline of tasks with progress, milestones, dependency arrows and a today line. The task list is a table for assistive tech.
Import
import { Gantt } from '@marbleui/ui'Props
<Gantt>
| Prop | Type | Default | Description |
|---|---|---|---|
| aria-label *required | string | — | |
| tasks *required | GanttTask[] | — | |
| className | string | — | |
| dayWidth | number | 28 | Pixels per day. |
Usage notes
Gantt draws a read-only project timeline beside a task table: bars with progress, milestones, dependency arrows, weekend shading and a today line. For meetings and dated events use EventCalendar; for a history of events use Timeline.
<Gantt
aria-label="Website redesign schedule"
tasks={[
{ id: 'research', name: 'User research', start: new Date(2026, 9, 1), end: new Date(2026, 9, 9), progress: 100, color: 3 },
{ id: 'build', name: 'Build components', start: new Date(2026, 9, 12), end: new Date(2026, 9, 26), progress: 40, dependsOn: ['research'] },
{ id: 'launch', name: 'Launch', start: new Date(2026, 9, 28), end: new Date(2026, 9, 28), milestone: true, dependsOn: ['build'] },
]}
/>
- Rows follow the order of
tasks, and the date range is fitted to them. Tasks with agroupare listed under a header row per group (groups in order of first appearance, ungrouped tasks first); in the table each group is its own row group.dayWidth(pixels per day, default 28) sets the zoom. Milestones sit on theirenddate;colorpicks--chart-1…8. aria-labelnames the table, which is what assistive tech gets: each task’s name and due date. Start dates, progress and dependencies are only drawn, with a tooltip on pointer hover, so put anything essential in the name.- The timeline is a focusable scroll region that keyboard users can scroll with the arrow keys. There’s no drag to reschedule and no click handler. Pass at least one task.
Example source · show· hide
import { useMemo } from 'react'
import { Gantt, type GanttTask } from './gantt'
function useTasks() {
return useMemo(() => {
const n = new Date()
const d = (o: number) => new Date(n.getFullYear(), n.getMonth(), n.getDate() + o)
const t: GanttTask[] = [
{ id: 'research', name: 'User research', start: d(-12), end: d(-4), progress: 100, color: 3 },
{ id: 'wire', name: 'Wireframes', start: d(-5), end: d(2), progress: 70, color: 1, dependsOn: ['research'] },
{ id: 'visual', name: 'Visual design', start: d(1), end: d(9), progress: 15, color: 7, dependsOn: ['wire'] },
{ id: 'build', name: 'Build components', start: d(4), end: d(18), progress: 5, color: 2, dependsOn: ['wire'] },
{ id: 'qa', name: 'QA & accessibility', start: d(16), end: d(22), color: 5, dependsOn: ['build', 'visual'] },
{ id: 'launch', name: 'Launch', start: d(23), end: d(23), milestone: true, color: 8, dependsOn: ['qa'] },
]
return t
}, [])
}
export const styles = {
Project: () => <Gantt aria-label="Website redesign schedule" tasks={useTasks()} className="w-[52rem]" />,
Grouped: () => {
const tasks = useTasks()
const phase: Record<string, string> = { research: 'Discovery', wire: 'Design', visual: 'Design', build: 'Delivery', qa: 'Delivery', launch: 'Delivery' }
return <Gantt aria-label="Website redesign schedule by phase" tasks={tasks.map((t) => ({ ...t, group: phase[t.id] }))} className="w-[52rem]" />
},
Compact: () => <Gantt aria-label="Website redesign schedule" tasks={useTasks()} dayWidth={16} className="w-[40rem]" />,
}Source: packages/ui/src/gantt/gantt.tsx
Catalog
- Category
- date-time
- Priority
- Pro
- Primitive
- custom