vue-svelte-gantt
v0.2.0
Published
Vue 3 wrapper component for svelte-gantt – interactive Gantt chart / resource booking
Maintainers
Readme
vue-svelte-gantt
Vue 3 wrapper for svelte-gantt — a lightweight, high-performance interactive Gantt chart / resource booking component.
Live Demo: https://gcasotti.github.io/vue-svelte-gantt
Repository: https://github.com/gcasotti/vue-svelte-gantt
No Svelte build tooling required. This package uses the pre-compiled svelte-gantt bundle via its imperative API.
Installation
npm install vue-svelte-gantt svelte-ganttBasic Usage
<script setup lang="ts">
import { ref } from 'vue';
import { SvelteGanttChart } from 'vue-svelte-gantt';
const from = ref(new Date(2025, 0, 1).valueOf());
const to = ref(new Date(2025, 0, 8).valueOf());
const rows = ref([
{ id: 1, label: 'Row 1' },
{ id: 2, label: 'Row 2' },
]);
const tasks = ref([
{
id: 1,
resourceId: 1,
label: 'Task 1',
from: new Date(2025, 0, 1, 8).valueOf(),
to: new Date(2025, 0, 1, 16).valueOf(),
},
{
id: 2,
resourceId: 2,
label: 'Task 2',
from: new Date(2025, 0, 2, 10).valueOf(),
to: new Date(2025, 0, 3, 12).valueOf(),
},
]);
</script>
<template>
<SvelteGanttChart
:rows="rows"
:tasks="tasks"
:from="from"
:to="to"
:row-height="52"
:headers="[
{ unit: 'day', format: 'MMMM Do' },
{ unit: 'hour', format: 'H:mm' },
]"
@tasks-select="(task) => console.log('Selected:', task)"
@tasks-changed="(e) => console.log('Changed:', e)"
/>
</template>Usage with Dependencies Module
<script setup lang="ts">
import { ref } from 'vue';
import {
SvelteGanttChart,
SvelteGanttTable,
SvelteGanttDependencies,
} from 'vue-svelte-gantt';
const from = ref(new Date(2025, 0, 1).valueOf());
const to = ref(new Date(2025, 0, 8).valueOf());
const rows = ref([
{ id: 1, label: 'Planning' },
{ id: 2, label: 'Development' },
{ id: 3, label: 'Testing' },
]);
const tasks = ref([
{
id: 1,
resourceId: 1,
label: 'Design',
from: new Date(2025, 0, 1, 8).valueOf(),
to: new Date(2025, 0, 2, 17).valueOf(),
},
{
id: 2,
resourceId: 2,
label: 'Implement',
from: new Date(2025, 0, 3, 8).valueOf(),
to: new Date(2025, 0, 5, 17).valueOf(),
},
{
id: 3,
resourceId: 3,
label: 'QA',
from: new Date(2025, 0, 6, 8).valueOf(),
to: new Date(2025, 0, 7, 17).valueOf(),
},
]);
const dependencies = ref([
{ id: 1, fromId: 1, toId: 2 },
{ id: 2, fromId: 2, toId: 3 },
]);
const ganttRef = ref<InstanceType<typeof SvelteGanttChart> | null>(null);
function scrollToFirstTask() {
ganttRef.value?.scrollToTask(1, 'smooth');
}
</script>
<template>
<button @click="scrollToFirstTask">Scroll to Task 1</button>
<SvelteGanttChart
ref="ganttRef"
:rows="rows"
:tasks="tasks"
:from="from"
:to="to"
:gantt-table-modules="[SvelteGanttTable]"
:gantt-body-modules="[SvelteGanttDependencies]"
:table-width="200"
:dependencies="dependencies"
:row-height="52"
:headers="[
{ unit: 'day', format: 'ddd D MMM' },
{ unit: 'hour', format: 'HH' },
]"
@tasks-changed="(e) => console.log('Task changed:', e)"
@tasks-dblclicked="(task, event) => console.log('Double clicked:', task)"
/>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| rows | RowModel[] | required | Rows to display |
| from | number \| Date | required | Timeline start datetime |
| to | number \| Date | required | Timeline end datetime |
| tasks | TaskModel[] | [] | Tasks to display |
| timeRanges | TimeRangeModel[] | [] | Time ranges to display |
| rowHeight | number | 52 | Height of a single row (px) |
| rowPadding | number | 6 | Top and bottom padding of a row (px) |
| minWidth | number | 800 | Minimum width of the gantt area (px) |
| fitWidth | boolean | false | Stretch timeline to fit container |
| tableWidth | number | 240 | Width of the table (when using SvelteGanttTable) |
| resizeHandleWidth | number | 10 | Width of task resize handle (px) |
| classes | string \| string[] | [] | CSS classes for the gantt root |
| headers | GanttHeader[] | [...] | List of headers (unit + format) |
| zoomLevels | ZoomLevel[] | [...] | Zoom configurations (ctrl+scroll) |
| columnStrokeColor | string | '#efefef' | Column separator stroke color |
| columnStrokeWidth | number | 1 | Column separator stroke width |
| useCanvasColumns | boolean | true | Render columns in canvas for performance |
| highlightedDurations | HighlightedDurations | undefined | Highlighted time periods (e.g. weekends) |
| highlightColor | string | '#6eb859' | Color for highlighted durations |
| layout | 'overlap' \| 'pack' \| 'expand' | 'overlap' | Task layout strategy |
| columnUnit | string | 'minute' | Duration unit for columns |
| columnOffset | number | 15 | Duration width of a column |
| magnetUnit | string | 'minute' | Time unit for date snapping |
| magnetOffset | number | 15 | Amount of units for date snapping |
| ganttTableModules | unknown[] | [] | Table modules (e.g. [SvelteGanttTable]) |
| ganttBodyModules | unknown[] | [] | Body modules (e.g. [SvelteGanttDependencies]) |
| reflectOnParentRows | boolean | true | Show child-row tasks on parent rows |
| reflectOnChildRows | boolean | false | Show parent-row tasks on child rows |
| taskContent | (task) => string | null | Custom task content HTML |
| taskElementHook | (node, task) => void | null | Hook to access task DOM node |
| onTaskButtonClick | (task) => void | null | Task button click handler |
| dateAdapter | SvelteGanttDateAdapter | DefaultAdapter | Custom date adapter |
| enableCreateTask | boolean | false | Enable creating tasks by dragging |
| onCreateTask | (e) => TaskModel | (built-in) | Factory for new tasks on drag-create |
| onCreatedTask | (task) => void | noop | Callback after task creation |
Events
| Event | Payload | Description |
| --- | --- | --- |
| tasks-move | [TaskModel] | Task is being dragged |
| tasks-resize | [TaskModel] | Task is being resized |
| tasks-select | [SvelteTask] | Task was selected |
| tasks-switchRow | [task, targetRow, sourceRow] | Task moved to a different row |
| tasks-moveEnd | [TaskModel] | Task drag ended |
| tasks-change | [{ task, sourceRow, targetRow, previousState }] | Task changed (before update) |
| tasks-changed | [{ task, sourceRow, targetRow, previousState }] | Task changed (after update) |
| tasks-dblclicked | [SvelteTask, MouseEvent] | Task double-clicked |
| gantt-viewChanged | — | Zoom level changed |
| gantt-dateSelected | [{ from, to }] | Date range selected in header |
| timeranges-clicked | [{ model }] | Time range clicked |
| timeranges-resized | [{ model, left, width }] | Time range resized |
| timeranges-changed | [{ model, left, width }] | Time range changed |
Exposed Methods
Access these via a template ref:
const ganttRef = ref<InstanceType<typeof SvelteGanttChart>>();
// Then use:
ganttRef.value?.updateTask(taskModel);
ganttRef.value?.scrollToTask(taskId, 'smooth');| Method | Signature | Description |
| --- | --- | --- |
| getGanttInstance | () => SvelteGantt | Get the raw svelte-gantt instance |
| updateTask | (model: TaskModel) => void | Add or update a single task |
| updateTasks | (models: TaskModel[]) => void | Add or update multiple tasks |
| removeTask | (taskId: PropertyKey) => void | Remove a task |
| removeTasks | (taskIds: PropertyKey[]) => void | Remove multiple tasks |
| getTask | (id: PropertyKey) => SvelteTask | Get a task by ID |
| getTasks | (resourceId: PropertyKey) => SvelteTask[] | Get tasks for a row |
| updateRow | (model: RowModel) => void | Add or update a row |
| updateRows | (models: RowModel[]) => void | Add or update multiple rows |
| getRow | (resourceId: PropertyKey) => SvelteRow | Get a row by ID |
| selectTask | (id: PropertyKey) => void | Select a task |
| unselectTasks | () => void | Deselect all tasks |
| scrollToRow | (id, behavior?) => void | Scroll to a row |
| scrollToTask | (id, behavior?) => void | Scroll to a task |
| refreshTasks | () => void | Recalculate task positions |
| refreshTimeRanges | () => void | Recalculate time range positions |
| updateLayout | () => void | Force layout recalculation |
| getRowContainer | () => HTMLElement | Get the row container DOM element |
Re-exported Modules
These are re-exported from svelte-gantt for convenience:
import {
SvelteGanttTable,
SvelteGanttDependencies,
SvelteGanttExternal,
MomentSvelteGanttDateAdapter,
} from 'vue-svelte-gantt';How It Works
This wrapper uses the imperative Svelte API (new SvelteGantt(), $set(), $destroy()) to mount the pre-compiled svelte-gantt bundle inside a Vue component. All reactive props are deep-unwrapped with toRaw() before being passed to Svelte to avoid Vue Proxy incompatibilities.
License
MIT
