Gantt Chart

Task timeline with durations/dependencies.

Q3 launch plan
Research
Research
Design
Design
Build
Build
Test
Test
Launch
Launch
Task summary
TaskStartEnd
ResearchWeek 1Week 2
DesignWeek 2Week 3
BuildWeek 3Week 5
TestWeek 5Week 5.5
LaunchWeek 6Week 6

html

<figure class="gantt-demo gantt-demo--comfortable" style="--accent:#E8A020;">
  <figcaption class="gantt-demo__title">Q3 launch plan</figcaption>
  <div class="gantt-demo__chart">
    <div class="gantt-demo__header" aria-hidden="true">
      <span class="gantt-demo__tick">Week 1</span>
      <span class="gantt-demo__tick">Week 2</span>
      <span class="gantt-demo__tick">Week 3</span>
      <span class="gantt-demo__tick">Week 4</span>
      <span class="gantt-demo__tick">Week 5</span>
      <span class="gantt-demo__tick">Week 6</span>
    </div>
    <div class="gantt-demo__row">
      <span class="gantt-demo__label">Research</span>
      <div class="gantt-demo__track">
        <div class="gantt-demo__bar" style="left:0%;width:33.3%;">Research</div>
      </div>
    </div>
    <div class="gantt-demo__row">
      <span class="gantt-demo__label">Design</span>
      <div class="gantt-demo__track">
        <div class="gantt-demo__bar" style="left:16.7%;width:33.3%;">Design</div>
        <div class="gantt-demo__dep" style="left:49.5%;width:16.8%;" aria-hidden="true"></div>
      </div>
    </div>
    <div class="gantt-demo__row">
      <span class="gantt-demo__label">Build</span>
      <div class="gantt-demo__track">
        <div class="gantt-demo__bar gantt-demo__bar--critical" style="left:33.3%;width:50%;">Build</div>
      </div>
    </div>
    <div class="gantt-demo__row">
      <span class="gantt-demo__label">Test</span>
      <div class="gantt-demo__track">
        <div class="gantt-demo__bar" style="left:66.7%;width:25%;">Test</div>
      </div>
    </div>
    <div class="gantt-demo__row">
      <span class="gantt-demo__label">Launch</span>
      <div class="gantt-demo__track">
        <div class="gantt-demo__bar gantt-demo__bar--milestone" style="left:91.7%;width:8.3%;">Launch</div>
      </div>
    </div>
  </div>
  <table class="gantt-demo__summary">
    <caption>Task summary</caption>
    <thead>
      <tr><th scope="col">Task</th><th scope="col">Start</th><th scope="col">End</th></tr>
    </thead>
    <tbody>
      <tr><th scope="row">Research</th><td>Week 1</td><td>Week 2</td></tr>
      <tr><th scope="row">Design</th><td>Week 2</td><td>Week 3</td></tr>
      <tr><th scope="row">Build</th><td>Week 3</td><td>Week 5</td></tr>
      <tr><th scope="row">Test</th><td>Week 5</td><td>Week 5.5</td></tr>
      <tr><th scope="row">Launch</th><td>Week 6</td><td>Week 6</td></tr>
    </tbody>
  </table>
</figure>
<style>
.gantt-demo { font: 13px/1.4 system-ui, sans-serif; color: #241430; background: #FAF7F2; border: 1.5px solid #24143022; border-radius: 12px; padding: 18px; box-sizing: border-box; }
.gantt-demo__title { font-size: 15px; font-weight: 600; margin-bottom: 14px; }
.gantt-demo__chart { display: flex; flex-direction: column; gap: 10px; }
.gantt-demo--compact .gantt-demo__chart { gap: 4px; }
.gantt-demo__header { display: flex; padding-left: 90px; margin-bottom: 4px; }
.gantt-demo__tick { flex: 1; font-size: 10px; color: #24143099; text-transform: uppercase; letter-spacing: .03em; }
.gantt-demo__row { display: flex; align-items: center; gap: 8px; }
.gantt-demo__label { width: 82px; flex-shrink: 0; font-size: 12px; font-weight: 600; }
.gantt-demo__track { position: relative; flex: 1; height: 22px; background: #24143010; border-radius: 6px; }
.gantt-demo--compact .gantt-demo__track { height: 16px; }
.gantt-demo__bar { position: absolute; top: 0; bottom: 0; background: var(--accent); border-radius: 6px; color: #241430; font-size: 11px; font-weight: 600; display: flex; align-items: center; padding: 0 8px; white-space: nowrap; overflow: hidden; }
.gantt-demo__bar--critical { background: #241430; color: #FAF7F2; }
.gantt-demo__bar--milestone { background: #F5C2E0; }
.gantt-demo__dep { position: absolute; top: -10px; height: 2px; background: #24143055; }
.gantt-demo__summary { margin-top: 16px; width: 100%; border-collapse: collapse; font-size: 11px; }
.gantt-demo__summary caption { text-align: left; font-size: 11px; color: #24143099; margin-bottom: 4px; }
.gantt-demo__summary th, .gantt-demo__summary td { text-align: left; padding: 3px 8px 3px 0; border-bottom: 1px solid #24143014; }
</style>

tailwind

<figure class="gantt-tw gantt-tw--comfortable font-sans text-[13px] text-[#241430] bg-[#FAF7F2] border-[1.5px] border-[#24143022] rounded-xl p-[18px] box-border" style="--accent:#E8A020;">
  <figcaption class="text-[15px] font-semibold mb-3.5">Q3 launch plan</figcaption>
  <div class="gantt-tw__chart flex flex-col gap-2.5">
    <div class="gantt-tw__header flex pl-[90px] mb-1" aria-hidden="true">
      <span class="flex-1 text-[10px] uppercase tracking-wide text-[#241430]/60">Week 1</span>
      <span class="flex-1 text-[10px] uppercase tracking-wide text-[#241430]/60">Week 2</span>
      <span class="flex-1 text-[10px] uppercase tracking-wide text-[#241430]/60">Week 3</span>
      <span class="flex-1 text-[10px] uppercase tracking-wide text-[#241430]/60">Week 4</span>
      <span class="flex-1 text-[10px] uppercase tracking-wide text-[#241430]/60">Week 5</span>
      <span class="flex-1 text-[10px] uppercase tracking-wide text-[#241430]/60">Week 6</span>
    </div>
    <div class="flex items-center gap-2">
      <span class="w-[82px] shrink-0 text-xs font-semibold">Research</span>
      <div class="gantt-tw__track relative flex-1 bg-[#24143010] rounded-md">
        <div class="gantt-tw__bar absolute inset-y-0 rounded-md text-[#241430] text-[11px] font-semibold flex items-center px-2 whitespace-nowrap overflow-hidden" style="left:0%;width:33.3%;background:#E8A020;">Research</div>
      </div>
    </div>
    <div class="flex items-center gap-2">
      <span class="w-[82px] shrink-0 text-xs font-semibold">Design</span>
      <div class="gantt-tw__track relative flex-1 bg-[#24143010] rounded-md">
        <div class="gantt-tw__bar absolute inset-y-0 rounded-md text-[#241430] text-[11px] font-semibold flex items-center px-2 whitespace-nowrap overflow-hidden" style="left:16.7%;width:33.3%;background:#E8A020;">Design</div>
        <div class="absolute h-0.5 bg-[#24143055]" style="top:-10px;left:49.5%;width:16.8%;" aria-hidden="true"></div>
      </div>
    </div>
    <div class="flex items-center gap-2">
      <span class="w-[82px] shrink-0 text-xs font-semibold">Build</span>
      <div class="gantt-tw__track relative flex-1 bg-[#24143010] rounded-md">
        <div class="gantt-tw__bar absolute inset-y-0 rounded-md text-[#FAF7F2] text-[11px] font-semibold flex items-center px-2 whitespace-nowrap overflow-hidden bg-[#241430]" style="left:33.3%;width:50%;">Build</div>
      </div>
    </div>
    <div class="flex items-center gap-2">
      <span class="w-[82px] shrink-0 text-xs font-semibold">Test</span>
      <div class="gantt-tw__track relative flex-1 bg-[#24143010] rounded-md">
        <div class="gantt-tw__bar absolute inset-y-0 rounded-md text-[#241430] text-[11px] font-semibold flex items-center px-2 whitespace-nowrap overflow-hidden" style="left:66.7%;width:25%;background:#E8A020;">Test</div>
      </div>
    </div>
    <div class="flex items-center gap-2">
      <span class="w-[82px] shrink-0 text-xs font-semibold">Launch</span>
      <div class="gantt-tw__track relative flex-1 bg-[#24143010] rounded-md">
        <div class="gantt-tw__bar absolute inset-y-0 rounded-md text-[#241430] text-[11px] font-semibold flex items-center px-2 whitespace-nowrap overflow-hidden bg-[#F5C2E0]" style="left:91.7%;width:8.3%;">Launch</div>
      </div>
    </div>
  </div>
  <table class="gantt-tw__summary mt-4 w-full border-collapse text-[11px]">
    <caption class="text-left text-[11px] text-[#241430]/60 mb-1">Task summary</caption>
    <thead>
      <tr><th scope="col" class="text-left py-1 pr-2 border-b border-[#24143014]">Task</th><th scope="col" class="text-left py-1 pr-2 border-b border-[#24143014]">Start</th><th scope="col" class="text-left py-1 pr-2 border-b border-[#24143014]">End</th></tr>
    </thead>
    <tbody>
      <tr><th scope="row" class="text-left py-1 pr-2 border-b border-[#24143014] font-normal">Research</th><td class="py-1 pr-2 border-b border-[#24143014]">Week 1</td><td class="py-1 pr-2 border-b border-[#24143014]">Week 2</td></tr>
      <tr><th scope="row" class="text-left py-1 pr-2 border-b border-[#24143014] font-normal">Design</th><td class="py-1 pr-2 border-b border-[#24143014]">Week 2</td><td class="py-1 pr-2 border-b border-[#24143014]">Week 3</td></tr>
      <tr><th scope="row" class="text-left py-1 pr-2 border-b border-[#24143014] font-normal">Build</th><td class="py-1 pr-2 border-b border-[#24143014]">Week 3</td><td class="py-1 pr-2 border-b border-[#24143014]">Week 5</td></tr>
      <tr><th scope="row" class="text-left py-1 pr-2 border-b border-[#24143014] font-normal">Test</th><td class="py-1 pr-2 border-b border-[#24143014]">Week 5</td><td class="py-1 pr-2 border-b border-[#24143014]">Week 5.5</td></tr>
      <tr><th scope="row" class="text-left py-1 pr-2 font-normal">Launch</th><td class="py-1 pr-2">Week 6</td><td class="py-1 pr-2">Week 6</td></tr>
    </tbody>
  </table>
</figure>
<style>
.gantt-tw--compact .gantt-tw__chart { gap: 4px; }
.gantt-tw--compact .gantt-tw__track { height: 16px; }
.gantt-tw__track { height: 22px; }
</style>

react

export function GanttChart({
  title = "Q3 launch plan",
  unit = "Week",
  density = "comfortable",
  accent = "#E8A020",
  dependency = true,
}) {
  const rows = [
    { label: "Research", left: 0, width: 33.3, fill: accent, text: "#241430" },
    { label: "Design", left: 16.7, width: 33.3, fill: accent, text: "#241430" },
    { label: "Build", left: 33.3, width: 50, fill: "#241430", text: "#FAF7F2" },
    { label: "Test", left: 66.7, width: 25, fill: accent, text: "#241430" },
    { label: "Launch", left: 91.7, width: 8.3, fill: "#F5C2E0", text: "#241430" },
  ];
  const summary = [
    { label: "Research", start: 1, end: 2 },
    { label: "Design", start: 2, end: 3 },
    { label: "Build", start: 3, end: 5 },
    { label: "Test", start: 5, end: 5.5 },
    { label: "Launch", start: 6, end: 6 },
  ];
  const trackHeight = density === "compact" ? 16 : 22;
  const rowGap = density === "compact" ? 4 : 10;
  return (
    <figure style={{ fontFamily: "system-ui, sans-serif", fontSize: 13, color: "#241430", background: "#FAF7F2", border: "1.5px solid #24143022", borderRadius: 12, padding: 18, boxSizing: "border-box" }}>
      <figcaption style={{ fontSize: 15, fontWeight: 600, marginBottom: 14 }}>{title}</figcaption>
      <div style={{ display: "flex", flexDirection: "column", gap: rowGap }}>
        <div style={{ display: "flex", paddingLeft: 90, marginBottom: 4 }} aria-hidden="true">
          {[1, 2, 3, 4, 5, 6].map((n) => (
            <span key={n} style={{ flex: 1, fontSize: 10, color: "#24143099", textTransform: "uppercase", letterSpacing: ".03em" }}>{unit} {n}</span>
          ))}
        </div>
        {rows.map((r) => (
          <div key={r.label} style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ width: 82, flexShrink: 0, fontSize: 12, fontWeight: 600 }}>{r.label}</span>
            <div style={{ position: "relative", flex: 1, height: trackHeight, background: "#24143010", borderRadius: 6 }}>
              <div style={{ position: "absolute", top: 0, bottom: 0, left: `${r.left}%`, width: `${r.width}%`, background: r.fill, color: r.text, borderRadius: 6, fontSize: 11, fontWeight: 600, display: "flex", alignItems: "center", padding: "0 8px", whiteSpace: "nowrap", overflow: "hidden" }}>{r.label}</div>
              {dependency && r.label === "Design" && (
                <div style={{ position: "absolute", top: -10, left: "49.5%", width: "16.8%", height: 2, background: "#24143055" }} aria-hidden="true" />
              )}
            </div>
          </div>
        ))}
      </div>
      <table style={{ marginTop: 16, width: "100%", borderCollapse: "collapse", fontSize: 11 }}>
        <caption style={{ textAlign: "left", fontSize: 11, color: "#24143099", marginBottom: 4 }}>Task summary</caption>
        <thead>
          <tr>
            <th scope="col" style={{ textAlign: "left", padding: "3px 8px 3px 0", borderBottom: "1px solid #24143014" }}>Task</th>
            <th scope="col" style={{ textAlign: "left", padding: "3px 8px 3px 0", borderBottom: "1px solid #24143014" }}>Start</th>
            <th scope="col" style={{ textAlign: "left", padding: "3px 8px 3px 0", borderBottom: "1px solid #24143014" }}>End</th>
          </tr>
        </thead>
        <tbody>
          {summary.map((s) => (
            <tr key={s.label}>
              <th scope="row" style={{ textAlign: "left", fontWeight: 400, padding: "3px 8px 3px 0", borderBottom: "1px solid #24143014" }}>{s.label}</th>
              <td style={{ padding: "3px 8px 3px 0", borderBottom: "1px solid #24143014" }}>{unit} {s.start}</td>
              <td style={{ padding: "3px 8px 3px 0", borderBottom: "1px solid #24143014" }}>{unit} {s.end}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </figure>
  );
}