Installation
Packages
Section titled “Packages”Install the package you import from. @ganttlane/dom brings @ganttlane/core with it, and
@ganttlane/react brings both.
pnpm add @ganttlane/domnpm install @ganttlane/domyarn add @ganttlane/dombun add @ganttlane/dompnpm add @ganttlane/react react react-domnpm install @ganttlane/react react react-domyarn add @ganttlane/react react react-dombun add @ganttlane/react react react-domAn app that already has react and react-dom needs only @ganttlane/react.
pnpm add @ganttlane/corenpm install @ganttlane/coreyarn add @ganttlane/corebun add @ganttlane/coreFor a renderer of your own, scheduling on a server, or testing rules without a browser.
Requirements
Section titled “Requirements”- ESM only, with TypeScript declarations. TypeScript must resolve package
exports:moduleResolutionofbundler,node16ornodenext. - Browsers. The last two versions of Chrome, Edge, Firefox and Safari, and iOS Safari 16.4 or newer.
- React. 18.3 or 19;
reactandreact-domare peer dependencies (^18.3.0 || ^19.0.0). - Node. 20 or newer for
@ganttlane/core(a chart itself needs a DOM).
The stylesheet
Section titled “The stylesheet”The stylesheet is a separate import, once per page. The JavaScript never imports it, so bundlers,
CSS-in-JS setups and plain <link> tags all work.
import '@ganttlane/dom/styles.css';import '@ganttlane/react/styles.css';It is a copy of the stylesheet of @ganttlane/dom, so an app that installed only
@ganttlane/react can import it. Import one of the two, not both.
The CSS is in @layer gantt, so any style of your own wins without !important. Have it in effect
before you mount: the chart measures its container when it is created.
Without a bundler
Section titled “Without a bundler”A page with no build step can load the library from a CDN. Two routes; both give the same chart.
A <script> tag
Section titled “A <script> tag”@ganttlane/dom ships files for exactly this. The script sets one global, Ganttlane, with
everything @ganttlane/dom exports, plus createTaskList and fromFrappeGanttOptions. It has
no dependencies: the core, the date library and valibot are inside.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ganttlane/dom@0.5/dist/styles.min.css" /><script src="https://cdn.jsdelivr.net/npm/@ganttlane/dom@0.5/dist/ganttlane.global.prod.js"></script>
<div id="chart" style="height: 420px"></div><script>const gantt = Ganttlane.createGantt(document.getElementById('chart'), { tasks: [ { id: 'design', name: 'Design', start: '2026-03-02', end: '2026-03-06', progress: 60 }, { id: 'build', name: 'Build', start: '2026-03-09', end: '2026-03-20' }, ], links: [{ source: 'design', target: 'build' }],});</script>The files, all in dist/ of the package:
| File | What it is |
|---|---|
ganttlane.global.prod.js |
Minified, short issue messages. What https://cdn.jsdelivr.net/npm/@ganttlane/dom and unpkg serve when you give no file. |
ganttlane.global.js |
Readable, with the full issue messages and the hints for old option names (bar_height → layout.barHeight). Use it while you write the page, or while you move from frappe-gantt. |
styles.min.css |
styles.css, minified. |
THIRD-PARTY-LICENSES.txt |
The licences of the code inside the scripts (@internationalized/date, Apache-2.0; valibot, MIT). |
The production file is about 270 kB, 90 kB gzipped, because it holds the whole library with its
calendar; frappe-gantt’s single file is 25.6 kB. If you have a bundler, use the npm packages: they
are tree-shaken and cost less. There is no script file for @ganttlane/react: React apps have a
bundler, and the ES module route below covers the rest.
A module from an ESM CDN
Section titled “A module from an ESM CDN”<script type="module"> loads the npm package itself, with its dependencies, from a CDN that
turns npm packages into modules. No file of ours is involved.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ganttlane/dom@0.5/dist/styles.min.css" /><div id="chart" style="height: 420px"></div><script type="module">import { createGantt } from 'https://cdn.jsdelivr.net/npm/@ganttlane/dom@0.5/+esm';// or: from 'https://esm.sh/@ganttlane/dom@0.5'
createGantt(document.getElementById('chart'), { tasks: [] });
</script>Pin a version
Section titled “Pin a version”The URLs above name a range of versions (a minor version while the packages are 0.x, a major one from 1.0): you get fixes without editing the page, and a
breaking change (a new minor version while the packages are 0.x, a new major one after) never
reaches it. For a page that must not change at all, use the exact version, and add
Subresource Integrity
so that the browser refuses a file that differs from the one you tested. SRI works only with an exact
version, because a range serves different bytes over time:
curl -s https://cdn.jsdelivr.net/npm/@ganttlane/dom@0.5.0/dist/ganttlane.global.prod.js \| openssl dgst -sha384 -binary | openssl base64 -A<scriptsrc="https://cdn.jsdelivr.net/npm/@ganttlane/dom@0.5.0/dist/ganttlane.global.prod.js"integrity="sha384-<the output above>"crossorigin="anonymous"></script>Do the same for the stylesheet. Compute the hash from the file the CDN serves, as above, not from a local build.
Strict pnpm and Yarn Plug’n’Play
Section titled “Strict pnpm and Yarn Plug’n’Play”Strict pnpm and Yarn Plug’n’Play let you import only what your own package.json lists. @ganttlane/dom and
@ganttlane/react re-export the types you meet around a chart (Task, Link, TaskRecord,
ChangeSet, …), and @ganttlane/react also re-exports patchTasks. For a runtime value of the
core in a vanilla app (patchTasks, createGanttCore), add @ganttlane/core on the same version.
Draw your first chart, or open an example.