React/Next.js starter
React
This example runs from source. Open the repository to clone, build, and run it locally.
Open on GitHubReact
Next.js starter
Next.js project that renders a Gantt chart in a client component, with task and link data wired in.
- README.md
- page.tsx
- Gantt.tsx
- demoData.ts
README.md View on GitHub
# DHTMLX React Gantt with Next.js (App Router)
A quick-start demo of **DHTMLX React Gantt** integrated into a **Next.js** application using the **App Router**. Built with React 19, TypeScript, and Tailwind CSS — shows the correct `'use client'` pattern for mounting a browser-only Gantt chart inside a server-rendered Next.js page.
A companion tutorial walks through the integration step by step: [Next.js integration guide](https://docs.dhtmlx.com/gantt/integrations/react/nextjs/)
## What is DHTMLX React Gantt with Next.js Starter
This starter shows how to embed DHTMLX React Gantt inside a Next.js App Router application. DHTMLX Gantt is a browser-only component: it accesses the DOM on initialization and cannot run during server-side rendering. The demo solves this by placing the Gantt chart in a dedicated Client Component marked with `'use client'`, which tells Next.js to render it only on the client while the page itself remains a Server Component.
The Gantt component receives tasks, links, and configuration as props from the page, keeping the component stateless and reusable. Data is loaded from a static seed file with tasks, task dependencies (links), and time scale configuration, giving you a working project timeline with day, month, and year zoom levels and drag-and-drop task management out of the box.
## When to Use
- Use this demo when building a Next.js App Router application that needs a Gantt chart for project planning or task scheduling.
- Use this when you need a working reference for the `'use client'` pattern that correctly isolates DHTMLX Gantt from Next.js server-side rendering.
- Use this as a minimal starting point before adding state management (Zustand), a real data source, or API routes for task persistence.
- Use this when you want to understand the props-driven Gantt component pattern before extending it with callbacks and mutations.
## Quick Start
```bash
git clone https://github.com/DHTMLX/react-gantt-nextjs-starter
cd react-gantt-nextjs-starter
npm install
npm run dev
```
Open [http://localhost:3000](http://localhost:3000) in your browser.
### Production Build
```bash
npm run build
npm start
```
## Architecture
```
├── app/
│ ├── page.tsx # Server Component — loads seed data, renders Gantt
│ ├── layout.tsx # Root layout with global styles
│ └── globals.css # Global styles and Tailwind configuration
├── components/
│ └── Gantt/
│ └── Gantt.tsx # 'use client' component wrapping ReactGantt
├── data/
│ └── demoData.ts # Seed tasks, links, and zoom configuration
├── next.config.ts # Next.js configuration
└── postcss.config.mjs # PostCSS / Tailwind configuration
```
`page.tsx` is a Server Component that loads task and link data and passes it as props to `Gantt.tsx`. `Gantt.tsx` is a Client Component that handles all browser-specific Gantt initialization. This split keeps the server component clean while ensuring Gantt only runs in the browser.
## Key Patterns
- **`'use client'` boundary** — `Gantt.tsx` is marked as a Client Component, which is the correct Next.js App Router mechanism for keeping browser-only libraries out of SSR. Without this directive, Next.js will attempt to render Gantt on the server and throw DOM-related errors.
- **Props-driven Gantt component** — tasks, links, and zoom configuration are all passed as props from the Server Component page. The Gantt component holds no internal state, making it straightforward to replace the seed data with a real data fetch.
- **Tasks and links as separate props** — unlike a simple event list, DHTMLX Gantt requires both a tasks array and a links array (dependency arrows between tasks). The seed data in `demoData.ts` provides both, showing the expected data shape.
- **Time scale configuration in seed data** — zoom levels (day, month, year) are defined in `demoData.ts` alongside the tasks and links, so all initial Gantt configuration is co-located and easy to find.
## Features
| Feature | Details |
|---|---|
| Next.js App Router | Uses the current App Router architecture, not Pages Router |
| SSR-safe integration | `'use client'` directive isolates Gantt from server rendering |
| Tasks and links | Seed data includes both tasks and dependency links |
| Time scales | Day, month, and year zoom levels configured from seed data |
| Drag-and-drop | Task rescheduling and reordering |
| Props-driven config | Tasks, links, and zoom passed as props from the Server Component |
| TypeScript | Full type coverage for tasks, links, and Gantt config |
| Tailwind CSS | Utility-first styling via PostCSS |
| React 19 | Built on the latest React release |
| Next.js 16 | Uses current Next.js App Router architecture |
## Production Notes
This demo is a starter, not a production-ready application. Before going to production:
- **Replace static data** — `demoData.ts` is a seed file. Load real tasks and links in the page's Server Component using `fetch` or an ORM query, then pass them as props to the Gantt component. Consider adding Next.js API routes for task CRUD operations.
- **Add state management** — the demo has no mutation handling. See the [Zustand starter](https://github.com/DHTMLX/react-gantt-zustand-starter) for a pattern that routes Gantt mutations through a centralized store, or use the Zustand + TanStack Query progression for full server-backed state.
- **Add error boundaries and loading states** — wrap the Gantt Client Component in a `<Suspense>` boundary with a loading fallback for data fetching scenarios.
- **Gantt license** — DHTMLX React Gantt requires a valid commercial license for production use (see License section below).
## Related Resources
- [Next.js integration tutorial (official guide)](https://dhtmlx.com/blog/why-use-dhtmlx-gantt-for-react-with-next-js-in-project-management-apps/)
- [DHTMLX React Gantt product page](https://dhtmlx.com/docs/products/dhtmlxGantt-for-React/)
- [DHTMLX Gantt product page](https://dhtmlx.com/docs/products/dhtmlxGantt/)
- [DHTMLX Gantt documentation](https://docs.dhtmlx.com/gantt/)
- [React Gantt integration guide](https://docs.dhtmlx.com/gantt/web__react.html)
- [Gantt + Zustand starter (state management)](https://github.com/DHTMLX/react-gantt-zustand-starter)
- [Gantt + TanStack Query starter (server-backed state)](https://github.com/dhtmlx/react-gantt-tanstack-query-starter)
- [Next.js App Router documentation](https://nextjs.org/docs/app)
- [Community forum](https://forum.dhtmlx.com/)
- [Report an issue](https://github.com/DHTMLX/react-gantt-nextjs-starter/issues)
## License
The source code in this repository is released under the **MIT License**.
**Commercial License**
Required for proprietary or commercial applications. Includes access to PRO features, dedicated technical support, and long-term maintenance.
[Learn more →](https://dhtmlx.com/docs/products/dhtmlxGantt-for-React/#licensing)
**Try before you buy**
A free evaluation of DHTMLX React Gantt is available — no credit card required.
[Start your evaluation →](https://dhtmlx.com/docs/products/dhtmlxGantt-for-React/download.shtml)
app/page.tsx View on GitHub
import Gantt from '../components/Gantt/Gantt';
import { tasks, links } from '../data/demoData';
export default function HomePage() {
return (
<div style={{ height: '100vh', width: '100vw' }}>
<Gantt tasks={tasks} links={links} />
</div>
);
}
components/Gantt/Gantt.tsx View on GitHub
'use client';
import { useMemo, useRef } from 'react';
import Gantt, { ReactGanttRef, Task, Link, GanttConfig } from '@dhtmlx/trial-react-gantt';
import '@dhtmlx/trial-react-gantt/dist/react-gantt.css';
export interface GanttProps {
tasks: Task[];
links: Link[];
}
export default function GanttChart({ tasks, links }: GanttProps) {
const ganttRef = useRef<ReactGanttRef>(null);
const config: GanttConfig = useMemo(
() => ({
grid_width: 500,
scale_height: 90,
scales: [
{ unit: 'year', step: 1, date: '%Y' },
{ unit: 'month', step: 1, date: '%M' },
{ unit: 'day', step: 1, date: '%d %M' },
],
}),
[]
);
return (
<Gantt
ref={ganttRef}
tasks={tasks}
links={links}
config={config}
data={{
save: (entity: string, action: string, data: Task | Link, id: string | number) => {
console.log(`${entity} - ${action} - ${id}`, data);
},
}}
/>
);
}
data/demoData.ts View on GitHub
import type { Task, Link } from '@dhtmlx/trial-react-gantt';
export const tasks: Task[] = [
{
id: 1,
text: 'Office itinerancy',
type: 'project',
start_date: new Date(2025, 3, 2),
duration: 17,
progress: 0.4,
parent: 0,
open: true,
},
{
id: 2,
text: 'Office facing',
type: 'project',
start_date: new Date(2025, 3, 2),
duration: 8,
progress: 0.6,
parent: 1,
open: true,
},
{
id: 3,
text: 'Furniture installation',
type: 'project',
start_date: new Date(2025, 3, 11),
duration: 8,
progress: 0.6,
parent: 1,
open: true,
},
{
id: 4,
text: 'The employee relocation',
type: 'project',
start_date: new Date(2025, 3, 13),
duration: 5,
progress: 0.5,
parent: 1,
priority: 3,
open: true,
},
{
id: 5,
text: 'Interior office',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 7,
progress: 0.6,
parent: 2,
priority: 1,
},
{
id: 6,
text: 'Air conditioners check',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 7,
progress: 0.6,
parent: 2,
priority: 2,
},
{
id: 7,
text: 'Workplaces preparation',
type: 'task',
start_date: new Date(2025, 3, 12),
duration: 8,
progress: 0.6,
parent: 3,
},
{
id: 8,
text: 'Preparing workplaces',
type: 'task',
start_date: new Date(2025, 3, 14),
duration: 5,
progress: 0.5,
parent: 4,
priority: 1,
},
{
id: 9,
text: 'Workplaces importation',
type: 'task',
start_date: new Date(2025, 3, 21),
duration: 4,
progress: 0.5,
parent: 4,
},
{
id: 10,
text: 'Workplaces exportation',
type: 'task',
start_date: new Date(2025, 3, 27),
duration: 3,
progress: 0.5,
parent: 4,
priority: 2,
},
{
id: 11,
text: 'Product launch',
type: 'project',
start_date: new Date(2025, 3, 2),
duration: 13,
progress: 0.6,
parent: 0,
open: true,
},
{
id: 12,
text: 'Perform Initial testing',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 5,
progress: 1,
parent: 11,
},
{
id: 13,
text: 'Development',
type: 'project',
start_date: new Date(2025, 3, 3),
duration: 11,
progress: 0.5,
parent: 11,
open: true,
},
{ id: 14, text: 'Analysis', type: 'task', start_date: new Date(2025, 3, 3), duration: 6, progress: 0.8, parent: 11 },
{
id: 15,
text: 'Design',
type: 'project',
start_date: new Date(2025, 3, 3),
duration: 5,
progress: 0.2,
parent: 11,
open: true,
},
{
id: 16,
text: 'Documentation creation',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 7,
progress: 0,
parent: 11,
priority: 1,
},
{
id: 17,
text: 'Develop System',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 2,
progress: 1,
parent: 13,
priority: 2,
},
{
id: 25,
text: 'Beta Release',
type: 'milestone',
start_date: new Date(2025, 3, 6),
duration: 0,
progress: 0,
parent: 13,
},
{
id: 18,
text: 'Integrate System',
type: 'task',
start_date: new Date(2025, 3, 10),
duration: 2,
progress: 0.8,
parent: 13,
priority: 3,
},
{ id: 19, text: 'Test', type: 'task', start_date: new Date(2025, 3, 13), duration: 4, progress: 0.2, parent: 13 },
{
id: 20,
text: 'Marketing',
type: 'task',
start_date: new Date(2025, 3, 13),
duration: 4,
progress: 0,
parent: 13,
priority: 1,
},
{
id: 21,
text: 'Design database',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 4,
progress: 0.5,
parent: 15,
},
{
id: 22,
text: 'Software design',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 4,
progress: 0.1,
parent: 15,
priority: 1,
},
{
id: 23,
text: 'Interface setup',
type: 'task',
start_date: new Date(2025, 3, 3),
duration: 5,
progress: 0,
parent: 15,
priority: 1,
},
{
id: 24,
text: 'Release v1.0',
type: 'milestone',
start_date: new Date(2025, 3, 18),
duration: 0,
progress: 0,
parent: 11,
},
];
export const links: Link[] = [
{ id: 2, source: 2, target: 3, type: '0' },
{ id: 3, source: 3, target: 4, type: '0' },
{ id: 7, source: 8, target: 9, type: '0' },
{ id: 8, source: 9, target: 10, type: '0' },
{ id: 16, source: 17, target: 25, type: '0' },
{ id: 17, source: 18, target: 19, type: '0' },
{ id: 18, source: 19, target: 20, type: '0' },
{ id: 22, source: 13, target: 24, type: '0' },
{ id: 23, source: 25, target: 18, type: '0' },
];