A flexible, customizable Gantt chart component for React applications with drag-and-drop task scheduling, dark mode support, progress tracking, and multiple view modes.
- Features
- Installation
- Quick Start
- Components
- Task & TaskGroup Data Structure
- View Modes
- Customization
- Event Handling
- Dark Mode
- Advanced Examples
- Browser Support
- FAQ
- Contributing
- License
- π Interactive timeline with drag-and-drop task scheduling
- π¨ Fully customizable with CSS variables and custom classes
- π Multiple view modes (Day, Week, Month, Quarter, Year)
- π Dark mode support built-in
- π± Responsive design that works across devices
- π Progress tracking with visual indicators and interactive updates
- π Task dependencies and relationship management
- π― Event handling for clicks, updates, selections
- π§© Composable API with extensive custom render props for advanced customization
- π Smooth animations with configurable speeds and thresholds
- π Auto-scrolling during drag operations
npm install react-modern-gantt
yarn add react-modern-gantt
import React, { useState } from "react";
import GanttChart from "react-modern-gantt";
// β οΈ IMPORTANT: Don't forget to import the styles!
import "react-modern-gantt/dist/index.css";
function App() {
const [tasks, setTasks] = useState([
{
id: "team-1",
name: "Engineering",
description: "Development Team",
tasks: [
{
id: "task-1",
name: "Website Redesign",
startDate: new Date(2023, 0, 1),
endDate: new Date(2023, 2, 15),
color: "#3b82f6",
percent: 75,
},
// More tasks...
],
},
// More groups...
]);
const handleTaskUpdate = (groupId, updatedTask) => {
setTasks(prevTasks =>
prevTasks.map(group =>
group.id === groupId
? {
...group,
tasks: group.tasks.map(task => (task.id === updatedTask.id ? updatedTask : task)),
}
: group
)
);
};
return <GanttChart tasks={tasks} onTaskUpdate={handleTaskUpdate} darkMode={false} showProgress={true} />;
}
π Note: Make sure to import the CSS file to apply all necessary styles:
import "react-modern-gantt/dist/index.css";
Without this import, the component will not be styled correctly.
The Gantt chart requires CSS styles that are shipped separately from the component code. You have two options:
// In your application entry point (e.g., App.js or index.js)
import "react-modern-gantt/dist/index.css";
<!-- In your HTML file -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/index.css" />
GanttChart
: The main component for rendering a Gantt chartTaskItem
: Individual task barsTaskList
: The left sidebar with task groupsTimeline
: The header timeline displayViewModeSelector
: Controls for switching between timeline views
Tooltip
: Information tooltip for tasksTodayMarker
: Vertical line indicating the current date
interface Task {
id: string; // Unique identifier
name: string; // Task name
startDate: Date; // Start date
endDate: Date; // End date
color?: string; // Task color (CSS color value or hex code)
percent?: number; // Completion percentage (0-100)
dependencies?: string[]; // IDs of dependent tasks
[key: string]: any; // Additional custom properties
}
interface TaskGroup {
id: string; // Unique identifier
name: string; // Group name
description?: string; // Group description
icon?: string; // Optional icon (HTML string)
tasks: Task[]; // Array of tasks in this group
[key: string]: any; // Additional custom properties
}
The component supports five different view modes to adapt to different timeline needs:
View Mode | Description | Best Used For |
---|---|---|
DAY |
Shows days | Detailed short-term planning (days/weeks) |
WEEK |
Shows weeks | Short to medium-term planning (weeks/months) |
MONTH |
Shows months | Medium-term planning (months/quarters) |
QUARTER |
Shows quarters | Medium to long-term planning (quarters/year) |
YEAR |
Shows years | Long-term planning (years) |
import { GanttChart, ViewMode } from "react-modern-gantt";
// Using string literals
<GanttChart tasks={tasks} viewMode="day" />
// Using the ViewMode enum
<GanttChart tasks={tasks} viewMode={ViewMode.DAY} />
The easiest way to customize the appearance is by overriding CSS variables:
:root {
/* Primary colors */
--rmg-bg-color: #f8f9fb;
--rmg-text-color: #1a202c;
--rmg-border-color: #e2e8f0;
--rmg-task-color: #3182ce;
--rmg-task-text-color: white;
--rmg-marker-color: #e53e3e;
/* Size variables */
--rmg-row-height: 50px;
--rmg-task-height: 36px;
--rmg-border-radius: 6px;
/* Animation speed */
--rmg-animation-speed: 0.25;
}
<GanttChart
tasks={tasks}
styles={{
container: "my-gantt-container",
title: "my-gantt-title",
taskList: "my-task-list",
timeline: "my-timeline",
todayMarker: "my-today-marker",
taskRow: "my-task-row",
tooltip: "my-tooltip",
}}
onTaskUpdate={handleTaskUpdate}
/>
<GanttChart
tasks={tasks}
renderTask={({ task, leftPx, widthPx, topPx, isHovered, isDragging, showProgress }) => (
<div
className="my-custom-task"
style={{
position: "absolute",
left: `${leftPx}px`,
width: `${widthPx}px`,
top: `${topPx}px`,
backgroundColor: task.color || "#3182ce",
}}>
<div className="my-task-label">{task.name}</div>
{showProgress && (
<div className="my-progress-bar">
<div className="my-progress-fill" style={{ width: `${task.percent || 0}%` }} />
</div>
)}
</div>
)}
/>
Handle various interactions with the Gantt chart:
<GanttChart
tasks={tasks}
onTaskUpdate={(groupId, updatedTask) => {
console.log(`Task ${updatedTask.id} updated in group ${groupId}`);
// Update your state here
updateTasks(groupId, updatedTask);
}}
onTaskClick={(task, group) => {
console.log(`Task ${task.id} clicked in group ${group.id}`);
// Do something when a task is clicked
selectTask(task.id);
}}
onTaskSelect={(task, isSelected) => {
console.log(`Task ${task.id} selection state: ${isSelected}`);
// Handle selection state changes
}}
onGroupClick={group => {
console.log(`Group ${group.id} clicked`);
// Do something when a group is clicked
}}
onViewModeChange={viewMode => {
console.log(`View mode changed to: ${viewMode}`);
// Handle view mode changes
}}
/>
Dark mode is built-in and easy to enable:
<GanttChart tasks={tasks} darkMode={true} onTaskUpdate={handleTaskUpdate} />
<GanttChart
tasks={tasks}
getTaskColor={({ task }) => {
// Task is complete
if (task.percent === 100) {
return {
backgroundColor: "#22c55e", // Green
borderColor: "#166534",
textColor: "#ffffff",
};
}
// Task has dependencies
if (task.dependencies?.length > 0) {
return {
backgroundColor: "#f59e0b", // Orange
textColor: "#ffffff",
};
}
// High priority task
if (task.priority === "high") {
return {
backgroundColor: "#ef4444", // Red
textColor: "#ffffff",
};
}
// Default color
return {
backgroundColor: "#3b82f6", // Blue
textColor: "#ffffff",
};
}}
/>
<GanttChart
tasks={tasks}
renderTooltip={({ task, position, dragType, startDate, endDate }) => (
<div className="custom-tooltip">
<h3>{task.name}</h3>
{dragType && (
<div className="drag-indicator">{dragType === "move" ? "Moving task..." : "Resizing task..."}</div>
)}
<div className="date-range">
{format(startDate, "MMM d, yyyy")} - {format(endDate, "MMM d, yyyy")}
</div>
<div className="progress-section">
<div className="progress-label">Progress: {task.percent || 0}%</div>
<div className="progress-bar">
<div className="progress-fill" style={{ width: `${task.percent || 0}%` }} />
</div>
</div>
{task.assignee && <div className="assignee">Assigned to: {task.assignee}</div>}
</div>
)}
/>
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
Yes, you can use the locale
prop to change the date formatting:
<GanttChart
tasks={tasks}
locale="de-DE" // For German formatting
/>
The Gantt chart is a controlled component, so updates are handled through the onTaskUpdate
callback:
const handleTaskUpdate = (groupId, updatedTask) => {
setTasks(prevTasks =>
prevTasks.map(group =>
group.id === groupId
? {
...group,
tasks: group.tasks.map(task => (task.id === updatedTask.id ? updatedTask : task)),
}
: group
)
);
};
Yes, set the editMode
prop to false
:
<GanttChart tasks={tasks} editMode={false} />
Set the showProgress
prop to false
:
<GanttChart tasks={tasks} showProgress={false} />
Yes, use the getTaskColor
function:
<GanttChart
tasks={tasks}
getTaskColor={({ task }) => ({
backgroundColor: task.isUrgent ? "#ef4444" : "#3b82f6",
textColor: "white",
})}
/>
If your Gantt chart appears without styling, make sure you've imported the CSS file:
import "react-modern-gantt/dist/index.css";
This import should be included in your application's entry point or in the component where you use the Gantt chart.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.