Why Vue Teams Choose ApexGantt

The vue-apexgantt package exposes the chart as a real Vue 3 component, <ApexGanttChart />, with reactive props, typed emits, template refs, and a useGanttData composable, not a thin shell around an imperative library that leaves you fighting reactive proxies and template refs that don't behave like Vue components should. It shares its core engine with ApexGantt's React, Angular, and JavaScript wrappers, so the task data model stays consistent if your stack grows beyond Vue. Learn about the full ApexGantt component →

Drag-and-Drop Scheduling, Wired to Reactive State

Drag tasks to reschedule, resize bars, and draw dependency arrows on the timeline. Bind @task-update-success, which fires once for every committed edit, to update your reactive state, with @task-dragged and @task-resized for the gesture detail, and the chart reflects it. Watch the scripted plan move, then grab a bar yourself.


Critical Path That Recomputes on Every Edit

ApexGantt highlights the longest chain of dependent tasks that drives your finish date. Mutate a ref()-backed task or call update() on the template ref and the critical path recomputes automatically. Watch it re-route between the two branches below.


Baselines for Planned vs. Actual

Attach a planned (baseline) range to each task in the same tasks array and ApexGantt draws a thin reference bar beneath the live one, so schedule variance is visible at a glance. No separate data structure required. The demo drifts the actuals past plan to show a slipping project.


Continuous Zoom via a Single Prop

Bind the pixels-per-day prop (a number; the header tier auto-picks from year down to minute) to control timeline density reactively, with no data re-query. This one auto-zooms; interact to take the controls.

Task Dependencies

Finish-to-start, start-to-start, finish-to-finish, and start-to-finish links with lag, set on the :tasks you bind.

Milestones

Zero-duration diamond markers for gates, releases, and key dates.

Annotations

Pin sprint boundaries, deadlines, or notes to specific dates via options.annotations.

Resizable Sidebar

A resizable task list that adapts to long task names or more timeline room.

Rich HTML Tooltips

Templatable tooltips showing dates, duration, progress, and dependencies.

Custom Colors & Dark Theme

Bind :theme reactively for a runtime toggle; deeper styling via the options prop.

SVG, PNG and PDF Export

Export from the toolbar or with exportChart() on the instance. SVG stays vector with every task and dependency; PNG and PDF are images.

TypeScript Types

Definitions ship for the ApexGanttChart props, TaskInput, GanttUserOptions, ParsingConfig, and emits.

Install in Your Vue 3 App

ApexGantt for Vue requires two packages: the Vue wrapper and the core engine. It is a Vue 3 wrapper using the Composition API and requires Vue 3.3 or later (peer dependency vue ^3.3.0); Vue 2 is not supported.

npm install vue-apexgantt apexgantt
# or
pnpm add vue-apexgantt apexgantt
# or
yarn add vue-apexgantt apexgantt

A complete working Gantt chart in one Single File Component:

<template>
  <ApexGanttChart
    :tasks="tasks"
    :pixels-per-day="25.7"
    height="500px"
  />
</template>

<script setup lang="ts">
import { ref } from "vue"
import { ApexGanttChart } from "vue-apexgantt"
import type { TaskInput } from "vue-apexgantt"

const tasks = ref<TaskInput[]>([
  { id: "task-1", name: "Design",      startTime: "01-01-2026", endTime: "01-15-2026", progress: 75 },
  { id: "task-2", name: "Development", startTime: "01-16-2026", endTime: "02-28-2026", progress: 40, dependency: "task-1" },
  { id: "task-3", name: "QA",          startTime: "03-01-2026", endTime: "03-15-2026", progress: 0,  dependency: "task-2" }
])
</script>

Props use camelCase in script and kebab-case in templates (pixels-per-day, class-name).

Handling Events in Vue

Vue emits use kebab-case in templates. Bind handlers with @event-name, and reach imperative methods through a template ref:

<template>
  <ApexGanttChart
    ref="ganttRef"
    :tasks="tasks"
    :pixels-per-day="25.7"
    height="600px"
    @task-dragged="handleTaskDragged"
    @task-resized="handleTaskResized"
    @task-update-success="handleTaskUpdateSuccess"
  />

  <button @click="ganttRef?.zoomIn()">Zoom In</button>
  <button @click="ganttRef?.zoomOut()">Zoom Out</button>
</template>

<script setup lang="ts">
import { ref } from "vue"
import { ApexGanttChart } from "vue-apexgantt"
import type {
  TaskDraggedEventDetail,
  TaskResizedEventDetail,
  TaskUpdateSuccessEventDetail
} from "vue-apexgantt"

const ganttRef = ref<InstanceType<typeof ApexGanttChart> | null>(null)

const handleTaskDragged = (d: TaskDraggedEventDetail) => console.log("dragged", d)
const handleTaskResized = (d: TaskResizedEventDetail) => console.log("resized", d)
const handleTaskUpdateSuccess = async (d: TaskUpdateSuccessEventDetail) => {
  await fetch(`/api/tasks/${d.taskId}`, { method: "PATCH", body: JSON.stringify(d.updatedTask) })
}
</script>

The wrapper emits every core event, 20 with apexgantt 3.20, from taskUpdate and taskUpdateSuccess to taskProgressChanged, dependencyAdded, historyChange, and sortChange, bound in kebab-case. The template-ref methods are zoomIn, zoomOut, update, updateTask, destroy, and getInstance, which returns the chart instance for the rest of the API.

Customization and Theming

Bind :theme reactively for a runtime toggle, and pass a Partial<GanttUserOptions> through the options prop for deeper control:

<template>
  <ApexGanttChart :tasks="tasks" :theme="theme" :options="ganttOptions" />
  <button @click="theme = theme === 'light' ? 'dark' : 'light'">Toggle theme</button>
</template>

<script setup lang="ts">
import { ref } from "vue"
import { ApexGanttChart } from "vue-apexgantt"
import type { ThemeMode, GanttUserOptions, TaskInput } from "vue-apexgantt"

const tasks = ref<TaskInput[]>([
  { id: "task-1", name: "Design",      startTime: "01-01-2026", endTime: "01-15-2026", progress: 75 },
  { id: "task-2", name: "Development", startTime: "01-16-2026", endTime: "02-28-2026", progress: 40, dependency: "task-1" }
])

const theme = ref<ThemeMode>("light")

const ganttOptions: Partial<GanttUserOptions> = {
  enableTaskDrag: true,
  enableTaskResize: true,
  enableTaskEdit: true,
  barBackgroundColor: "#537CFA",
  rowBackgroundColors: ["#FFFFFF", "#F8F9FA"]
}
</script>

Mapping Your API Shape with useGanttData

API responses rarely match the field names ApexGantt expects. The useGanttData composable maps any shape, including nested paths via dot notation and value transforms, without hand-written code:

<script setup lang="ts">
import { ref } from "vue"
import { ApexGanttChart, useGanttData } from "vue-apexgantt"
import type { ParsingConfig } from "vue-apexgantt"

const apiData = ref([
  {
    project: {
      task:   { id: "T1", title: "Design" },
      dates:  { start: "01-01-2026", end: "01-15-2026" },
      status: { completion: 0.75 }
    }
  }
])

const parsingConfig: ParsingConfig = {
  id:        "project.task.id",
  name:      "project.task.title",
  startTime: "project.dates.start",
  endTime:   "project.dates.end",
  progress:  { key: "project.status.completion", transform: (v) => v * 100 }
}

const tasks = useGanttData({ data: apiData, parsing: parsingConfig })
</script>

<template>
  <ApexGanttChart :tasks="tasks" />
</template>

Dot notation pulls values from nested objects; the transform function converts unit-mismatched values, here a 0–1 completion ratio into a 0–100 percentage.

TypeScript Support in Vue

vue-apexgantt ships TypeScript definitions for every public surface:

import type {
  TaskInput,
  TaskType,
  ThemeMode,
  GanttUserOptions,
  ParsingConfig,
  TaskUpdateEventDetail,
  TaskUpdateSuccessEventDetail,
  TaskDraggedEventDetail,
  TaskResizedEventDetail
} from "vue-apexgantt"

Use these to type your refs, parsing configs, and event handlers. Volar picks them up in templates and <script setup> blocks.

Licence Key Setup

Set your licence key once at application start, before createApp().mount():

// main.ts
import { createApp } from "vue"
import { setApexGanttLicense } from "vue-apexgantt"
import App from "./App.vue"

setApexGanttLicense("your-license-key-here")

createApp(App).mount("#app")

ApexGantt is included in the Premium plan and above and has no free tier. Without a key it renders with a trial watermark for evaluation.

Performance with Large Vue Gantt Timelines

ApexGantt renders large project timelines quickly. On an Apple M4 Pro (apexgantt 3.11.1, headless Chromium):

~65 ms1,000 tasks
~275 ms5,000 tasks
~620 ms10,000 tasks

Vue Gantt Chart FAQ

How do I install ApexGantt for Vue?

Run npm install vue-apexgantt apexgantt. Both packages are required: vue-apexgantt is the Vue 3 wrapper, and apexgantt is the core engine. Import ApexGanttChart from vue-apexgantt and render it with a tasks prop.

Does ApexGantt work with Vue 2?

No. vue-apexgantt is a Vue 3 wrapper using the Composition API and requires Vue 3.3 or later (peer dependency vue ^3.3.0). Vue 2 is not supported.

How do I handle drag-and-drop updates in Vue state?

Bind task-update-success to a handler and update your reactive state (or save) there. With apexgantt 3.20 it fires once for every committed edit, whether a drag, resize, progress drag, dialog, inline or keyboard edit, with the updated task and a source field naming the path. task-dragged and task-resized add the gesture detail; save in one place only, or a drag is saved twice. The chart reflects the state you bind back.

Does ApexGantt support TypeScript in Vue?

Yes. Full TypeScript definitions ship with the package, including TaskInput, GanttUserOptions, ThemeMode, ParsingConfig, and event detail types like TaskDraggedEventDetail and TaskResizedEventDetail.

How do I parse API data that doesn't match the ApexGantt schema?

Use the useGanttData composable. Pass your raw data and a ParsingConfig mapping your field names to ApexGantt's (id, name, startTime, endTime, progress, dependency). Dot notation handles nested objects; a transform function handles unit conversions.

Does ApexGantt support critical path and baselines?

Yes. Critical path highlighting and baseline (planned-vs-actual) tracking are built in, configurable through GanttUserOptions. Worked demos live at /apexgantt/demos/critical-path/ and /apexgantt/demos/baseline/.

Can ApexGantt handle large timelines?

Yes. In a benchmark on an Apple M4 Pro, ApexGantt rendered a 5,000-task timeline in about 275 ms and a 10,000-task timeline in about 620 ms (apexgantt 3.11.1).

Ready to build your Vue project timeline?

The fastest path is the demos: running examples you can read and copy from.

See ApexGantt Demos