New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details → →
Socket
Book a DemoSign in
Socket

react-modern-gantt

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-modern-gantt

A modern, customizable Gantt chart component for React applications with export functionality

latest
Source
npmnpm
Version
0.8.5
Version published
Weekly downloads
1.4K
33.14%
Maintainers
1
Weekly downloads
Ā 
Created
Source

React Modern Gantt

A flexible, customizable Gantt chart component for React applications with drag-and-drop task scheduling, dark mode support, progress tracking, and multiple view modes.

npm version license bundle size

React Modern Gantt in Dark Mode

Live Demo

šŸ“‹ Table of Contents

✨ Features

  • šŸ“Š Interactive timeline with drag-and-drop task scheduling
  • šŸŽØ Fully customizable with CSS variables and custom classes
  • šŸ•’ Multiple view modes (Minute, Hour, 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
  • ⚔ Performance optimized for large timelines (Minute view limited to 500 intervals)
  • šŸ”„ Infinite scroll with automatic timeline extension (optional)
  • šŸŽÆ Focus mode to auto-scroll to current time when switching view modes

šŸ“¦ Installation

NPM

npm install react-modern-gantt

Yarn

yarn add react-modern-gantt

šŸš€ Quick Start

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}
      editMode={true}
      // Optional: Fine-tune editing behavior
      // allowProgressEdit={true}
      // allowTaskResize={true}
      // allowTaskMove={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.

Using CSS styles

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';

Option 2: Reference CSS in HTML

<!-- In your HTML file -->
<link rel="stylesheet" href="https://unpkg.com/react-modern-gantt@0.6.0/dist/index.css" />

🧩 Components

Main Components

  • GanttChart: The main component for rendering a Gantt chart
  • TaskItem: Individual task bars
  • TaskList: The left sidebar with task groups
  • Timeline: The header timeline display
  • ViewModeSelector: Controls for switching between timeline views

Utility Components

  • Tooltip: Information tooltip for tasks
  • TodayMarker: Vertical line indicating the current date

šŸ“Š Task & TaskGroup Data Structure

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
}

šŸ•’ View Modes

The component supports seven different view modes to adapt to different timeline needs, from granular hour-by-hour scheduling to long-term year planning:

View ModeDescriptionBest Used For
MINUTEShows minutesUltra-detailed short-term planning (minutes/hours)
HOURShows hoursDetailed hourly scheduling (hours/days)
DAYShows daysDetailed short-term planning (days/weeks)
WEEKShows weeksShort to medium-term planning (weeks/months)
MONTHShows monthsMedium-term planning (months/quarters)
QUARTERShows quartersMedium to long-term planning (quarters/year)
YEARShows yearsLong-term planning (years)
import { GanttChart, ViewMode } from "react-modern-gantt";

// Using string literals
<GanttChart tasks={tasks} viewMode="hour" />

// Using the ViewMode enum for hourly view
<GanttChart tasks={tasks} viewMode={ViewMode.HOUR} />

// Enable all view modes including MINUTE and HOUR
<GanttChart
    tasks={tasks}
    viewMode={ViewMode.HOUR}
    viewModes={[
        ViewMode.MINUTE,
        ViewMode.HOUR,
        ViewMode.DAY,
        ViewMode.WEEK,
        ViewMode.MONTH,
        ViewMode.QUARTER,
        ViewMode.YEAR,
    ]}
/>

Hour and Minute Views

The Hour and Minute views are perfect for detailed scheduling:

  • Hour View: Shows tasks on an hourly timeline, ideal for daily schedules, meeting planning, and shift management
  • Minute View: Shows tasks with minute-level precision (configurable step intervals)
// Hourly schedule example
const hourlyTasks = [
  {
    id: 'today',
    name: "Today's Schedule",
    tasks: [
      {
        id: 'meeting-1',
        name: 'Team Standup',
        startDate: new Date(2024, 0, 15, 9, 0), // 9:00 AM
        endDate: new Date(2024, 0, 15, 9, 30), // 9:30 AM
        percent: 100,
      },
      {
        id: 'meeting-2',
        name: 'Client Meeting',
        startDate: new Date(2024, 0, 15, 14, 0), // 2:00 PM
        endDate: new Date(2024, 0, 15, 15, 30), // 3:30 PM
        percent: 50,
      },
    ],
  },
];

<GanttChart tasks={hourlyTasks} viewMode={ViewMode.HOUR} showProgress={true} />;

šŸ“Š Interactive Progress Editing

React Modern Gantt includes a powerful interactive progress editing feature that allows users to adjust task completion percentages directly on the chart with a smooth, intuitive interface.

How It Works

When editMode={true} and showProgress={true}, each task displays a progress bar with an interactive handle (a draggable blob) at the end of the progress fill. Users can:

  • Hover over a task to reveal the progress handle
  • Drag the handle left or right to adjust the completion percentage
  • See a real-time percentage tooltip showing the current value while dragging
  • Click anywhere on the progress bar to jump to that percentage

Features

šŸŽÆ Percentage tooltip - Shows exact percentage (e.g., "75%") while dragging šŸŽØ Visual feedback - Handle scales up on hover and during drag 🚫 Conflict-free - Progress editing doesn't interfere with task movement/resizing šŸ”’ Constrained - Automatically clamps values between 0% and 100%

Usage Example

import React, { useState } from 'react';
import GanttChart from 'react-modern-gantt';
import 'react-modern-gantt/dist/index.css';

function App() {
  const [tasks, setTasks] = useState([
    {
      id: 'team-1',
      name: 'Development',
      tasks: [
        {
          id: 'task-1',
          name: 'Feature Implementation',
          startDate: new Date(2024, 0, 1),
          endDate: new Date(2024, 0, 15),
          percent: 65, // Initial progress
        },
      ],
    },
  ]);

  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
      )
    );

    // Log progress updates
    console.log(`Progress updated: ${updatedTask.name} - ${updatedTask.percent}%`);
  };

  return (
    <GanttChart
      tasks={tasks}
      editMode={true} // Enable editing
      showProgress={true} // Show progress bars
      onTaskUpdate={handleTaskUpdate}
    />
  );
}

Styling the Progress Bar

You can customize the progress bar appearance using CSS variables:

:root {
  /* Progress bar styling */
  --rmg-progress-bg: rgba(0, 0, 0, 0.2); /* Background track */
  --rmg-progress-fill: white; /* Progress fill color */

  /* Progress handle (draggable blob) */
  --rmg-task-color: #3b82f6; /* Handle border color */
}

/* Custom progress tooltip styling */
.rmg-progress-tooltip {
  background-color: var(--rmg-tooltip-bg);
  color: var(--rmg-tooltip-text);
  border: 1px solid var(--rmg-tooltip-border);
  font-weight: 600;
}

Best Practices

  • Enable both editMode and showProgress for interactive progress editing
  • Handle updates properly in onTaskUpdate to persist changes
  • Combine with hourly view for detailed daily task tracking
  • Use animations to provide smooth visual feedback (enabled by default)

Toggling Progress Editing

You have granular control over different editing features:

PropDescriptionDefaultNotes
editModeGlobal master switch for ALL editingtrueWhen false, disables everything
showProgressShows/hides progress barsfalseVisual display only
allowProgressEditEnables progress bar editingtrueRequires editMode=true AND showProgress=true
allowTaskResizeEnables task resizing (left/right handles)trueRequires editMode=true
allowTaskMoveEnables task movement (drag & drop)trueRequires editMode=true

Important: All granular permissions (allowProgressEdit, allowTaskResize, allowTaskMove) are ignored when editMode={false}.

Common Configurations

// 1. Fully editable (default behavior - no props needed)
<GanttChart tasks={tasks} />

// 2. Read-only with visible progress (no editing at all)
<GanttChart
  tasks={tasks}
  editMode={false}
  showProgress={true}
/>

// 3. Tasks movable but NOT resizable, no progress editing
<GanttChart
  tasks={tasks}
  editMode={true}
  allowTaskResize={false}
  showProgress={false}
/>

// 4. Progress visible but NOT editable, tasks fully editable
<GanttChart
  tasks={tasks}
  editMode={true}
  showProgress={true}
  allowProgressEdit={false}
/>

// 5. Tasks resizable but NOT movable
<GanttChart
  tasks={tasks}
  editMode={true}
  allowTaskMove={false}
  allowTaskResize={true}
/>

// 6. Only progress editing allowed (no task movement/resizing)
<GanttChart
  tasks={tasks}
  editMode={true}
  showProgress={true}
  allowTaskMove={false}
  allowTaskResize={false}
  allowProgressEdit={true}
/>

Permission Logic

The component uses a hierarchical permission system:

editMode (master switch)
  ā”œā”€ IF true:
  │   ā”œā”€ allowTaskMove → enables/disables task movement
  │   ā”œā”€ allowTaskResize → enables/disables resize handles
  │   └─ allowProgressEdit + showProgress → enables/disables progress editing
  └─ IF false:
      └─ ALL editing disabled (read-only mode)

šŸ”„ Infinite Scroll

Currently broken!!! Will be fixed in later versions

Usage Example

import React, { useState } from 'react';
import GanttChart from 'react-modern-gantt';
import { addMonths, subMonths } from 'date-fns';

function App() {
  const [tasks, setTasks] = useState([...]);
  const [startDate, setStartDate] = useState(subMonths(new Date(), 2));
  const [endDate, setEndDate] = useState(addMonths(new Date(), 4));

  const handleTimelineExtend = (direction, newStartDate, newEndDate) => {
    console.log(`Timeline extended ${direction}:`, newStartDate, newEndDate);

    // Update timeline boundaries
    setStartDate(newStartDate);
    setEndDate(newEndDate);

    // Optional: Load additional data for the new time range
    // fetchTasksForRange(newStartDate, newEndDate).then(setTasks);
  };

  return (
    <GanttChart
      tasks={tasks}
      startDate={startDate}
      endDate={endDate}
      infiniteScroll={true}
      onTimelineExtend={handleTimelineExtend}
      editMode={true}
    />
  );
}

Props

PropTypeDefaultDescription
tasksTaskGroup[]RequiredArray of task groups with nested tasks
viewModeViewModeDAYCurrent view mode (MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR)
viewModesViewMode[]All modesAvailable view modes in selector
editModebooleantrueMaster switch - enables/disables ALL editing features
allowProgressEditbooleantrueAllows progress bar editing (requires editMode=true)
allowTaskResizebooleantrueAllows task resizing with handles (requires editMode=true)
allowTaskMovebooleantrueAllows task movement via drag & drop (requires editMode=true)
showProgressbooleanfalseShows/hides progress bars on tasks
darkModebooleanfalseEnables dark mode theme
onTaskUpdate(groupId: string, task: Task) => void-Callback when task is updated
onTaskClick(groupId: string, task: Task) => void-Callback when task is clicked
startDateDateAuto-calculatedTimeline start date
endDateDateAuto-calculatedTimeline end date
minuteStepnumber5Interval between minute markers (Minute view only)
infiniteScrollbooleanfalseEnables automatic timeline extension
onTimelineExtend(direction: 'left' | 'right', newStartDate: Date, newEndDate: Date) => void-Callback when timeline extends (used with infiniteScroll)
focusModebooleantrueAuto-scroll to show current time when switching view modes

Permission Hierarchy:

  • editMode={false} → All editing disabled (read-only mode)
  • editMode={true} → Individual flags control specific features:
    • allowProgressEdit → Progress bar editing
    • allowTaskResize → Task resizing (left/right handles)
    • allowTaskMove → Task movement (drag & drop)

Best Practices

  • Use controlled dates with startDate and endDate props
  • Update state in onTimelineExtend to persist the new timeline range
  • Consider debouncing if loading data to prevent excessive API calls
  • Cache previously loaded data to avoid re-fetching

šŸŽÆ Focus Mode

React Modern Gantt includes a Focus Mode feature that automatically scrolls the timeline to show the current time indicator ("now") when switching between view modes. This is especially useful when working with time-sensitive views like Hour or Minute mode.

How It Works

By default (focusMode={true}), the timeline automatically centers on the current time whenever:

  • The view mode changes (e.g., switching from Month to Hour view)
  • The component initially renders
  • The focusMode prop is enabled

Usage Example

import React from 'react';
import GanttChart, { ViewMode } from 'react-modern-gantt';
import 'react-modern-gantt/dist/index.css';

function App() {
  return (
    <GanttChart
      tasks={tasks}
      viewMode={ViewMode.HOUR}
      focusMode={true}  // Enable auto-scroll to "now"
      showCurrentDateMarker={true}
      todayLabel="Now"
      viewModes={[
        ViewMode.MINUTE,
        ViewMode.HOUR,
        ViewMode.DAY,
        ViewMode.WEEK,
        ViewMode.MONTH,
      ]}
    />
  );
}

Use Cases

  • Daily scheduling: Automatically show current time when viewing hourly schedules
  • Real-time tracking: Keep the current time visible when monitoring active tasks
  • Time-sensitive workflows: Ensure users see "now" when switching between different time scales
  • Meeting schedules: Quickly focus on the current meeting or time slot

Props

PropTypeDefaultDescription
focusModebooleantrueAuto-scroll to current time when switching view modes
showCurrentDateMarkerbooleantrueShow/hide the current time indicator line
todayLabelstring"Today"Label for the current time marker

Programmatic Scrolling

You can also manually scroll to the current time using the ref API:

import React, { useRef } from 'react';
import GanttChart, { GanttChartRef } from 'react-modern-gantt';

function App() {
  const ganttRef = useRef<GanttChartRef>(null);

  const handleScrollToNow = () => {
    // Manually scroll to current time
    ganttRef.current?.scrollToToday();
  };

  return (
    <>
      <button onClick={handleScrollToNow}>Go to Now</button>
      <GanttChart
        ref={ganttRef}
        tasks={tasks}
        focusMode={false}  // Disable auto-scroll, using manual control instead
      />
    </>
  );
}

Best Practices

  • Enabled by default: Works great with ViewMode.HOUR or ViewMode.MINUTE
  • Combine with current date marker: Use showCurrentDateMarker={true} for visual reference
  • Disable when not needed: Set focusMode={false} for historical data or long-term planning views where current time is not relevant
  • Manual control: Use the scrollToToday() ref method for custom scroll behavior

šŸ“¤ Export Functionality

React Modern Gantt includes powerful export capabilities that allow you to export your Gantt chart as PNG, JPEG, or PDF files. You can also get the chart as a data URL or copy it directly to the clipboard.

Installation

To use the export functionality, you need to install the required dependencies:

npm install html2canvas jspdf

Basic Usage

Use the useGanttExport hook to access all export functions:

import React, { useState } from 'react';
import { GanttChart, useGanttExport } from 'react-modern-gantt';
import 'react-modern-gantt/dist/index.css';

function App() {
  const [tasks, setTasks] = useState([...]);

  // Get export functionality from the hook
  const {
    ganttRef,           // Ref to attach to GanttChart
    exportAsPng,        // Export as PNG
    exportAsJpeg,       // Export as JPEG
    exportAsPdf,        // Export as PDF
    exportChart,        // Custom export with options
    getDataUrl,         // Get as data URL
    copyToClipboard,    // Copy to clipboard
    checkDependencies,  // Check if dependencies are installed
  } = useGanttExport();

  const handleExportPng = async () => {
    await exportAsPng('my-gantt-chart');
  };

  const handleExportPdf = async () => {
    await exportAsPdf('my-gantt-chart');
  };

  return (
    <div>
      <div style={{ marginBottom: '1rem' }}>
        <button onClick={handleExportPng}>Export as PNG</button>
        <button onClick={handleExportPdf}>Export as PDF</button>
      </div>

      {/* IMPORTANT: Attach the ref to GanttChart */}
      <GanttChart
        ref={ganttRef}
        tasks={tasks}
        onTaskUpdate={setTasks}
      />
    </div>
  );
}

Export Methods

Export as PNG

const handleExportPng = async () => {
  await exportAsPng('gantt-chart'); // filename (without extension)
};

Export as JPEG

const handleExportJpeg = async () => {
  await exportAsJpeg('gantt-chart', 0.95); // filename, quality (0-1)
};

Export as PDF

const handleExportPdf = async () => {
  await exportAsPdf('gantt-chart'); // filename (without extension)
};

Custom Export with Options

const handleCustomExport = async () => {
  await exportChart({
    format: 'png',                    // 'png', 'jpeg', or 'pdf'
    filename: 'custom-export',        // filename without extension
    quality: 0.95,                    // image quality (0-1)
    scale: 2,                         // scale factor for higher resolution
    backgroundColor: '#ffffff',       // background color
  });
};

Get Data URL

const handleGetDataUrl = async () => {
  const dataUrl = await getDataUrl('png'); // 'png' or 'jpeg'

  // Use the data URL (e.g., display in an img tag)
  console.log(dataUrl);
};

Copy to Clipboard

const handleCopyToClipboard = async () => {
  const result = await copyToClipboard();

  if (result.success) {
    alert('Chart copied to clipboard!');
  } else {
    alert(`Error: ${result.error}`);
  }
};

Check Dependencies

You can check if the required export dependencies are installed:

import React, { useEffect, useState } from 'react';
import { useGanttExport } from 'react-modern-gantt';

function ExportComponent() {
  const { checkDependencies } = useGanttExport();
  const [deps, setDeps] = useState(null);

  useEffect(() => {
    const checkLibs = async () => {
      const dependencies = await checkDependencies();
      setDeps(dependencies);
    };
    checkLibs();
  }, [checkDependencies]);

  return (
    <div>
      {deps && (
        <div>
          <p>html2canvas: {deps.html2canvas ? 'āœ“ Installed' : 'āœ— Missing'}</p>
          <p>jsPDF: {deps.jspdf ? 'āœ“ Installed' : 'āœ— Missing'}</p>
        </div>
      )}
    </div>
  );
}

Export Options

OptionTypeDefaultDescription
formatstring'png'Export format: 'png', 'jpeg', or 'pdf'
filenamestring'gantt'Filename without extension
qualitynumber0.92Image quality (0-1, only for JPEG)
scalenumber1Scale factor for higher resolution
backgroundColorstring'#ffffff'Background color (CSS color value)

Best Practices

  • Install dependencies: Make sure to install html2canvas and jspdf for export functionality
  • Check dependencies: Use checkDependencies() to verify dependencies are available before enabling export features
  • Handle errors: Wrap export calls in try-catch blocks to handle potential errors gracefully
  • Higher quality: Use scale: 2 or higher for better resolution in exports
  • Dark mode exports: Set backgroundColor to match your chart's dark mode when exporting
  • User feedback: Show loading indicators and success/error messages during export operations

Complete Example with UI

import React, { useState, useEffect } from 'react';
import { GanttChart, useGanttExport } from 'react-modern-gantt';
import 'react-modern-gantt/dist/index.css';

function App() {
  const [tasks, setTasks] = useState([...]);
  const [darkMode, setDarkMode] = useState(false);
  const [exportStatus, setExportStatus] = useState('');
  const [dependencies, setDependencies] = useState(null);

  const {
    ganttRef,
    exportAsPng,
    exportAsPdf,
    checkDependencies,
  } = useGanttExport();

  // Check dependencies on mount
  useEffect(() => {
    const checkLibs = async () => {
      const deps = await checkDependencies();
      setDependencies(deps);
    };
    checkLibs();
  }, [checkDependencies]);

  const handleExport = async (exportFn, action) => {
    setExportStatus(`Exporting ${action}...`);
    try {
      await exportFn();
      setExportStatus(`āœ“ ${action} exported successfully!`);
    } catch (error) {
      setExportStatus(`āœ— Error: ${error.message}`);
    }
    setTimeout(() => setExportStatus(''), 3000);
  };

  return (
    <div>
      <div style={{ marginBottom: '1rem' }}>
        <button
          onClick={() => handleExport(() => exportAsPng('gantt'), 'PNG')}
          disabled={!dependencies?.html2canvas}
        >
          šŸ“„ Export PNG
        </button>
        <button
          onClick={() => handleExport(() => exportAsPdf('gantt'), 'PDF')}
          disabled={!dependencies?.html2canvas || !dependencies?.jspdf}
        >
          šŸ“„ Export PDF
        </button>
      </div>

      {exportStatus && (
        <div style={{
          padding: '0.75rem',
          backgroundColor: exportStatus.startsWith('āœ“') ? '#10b981' : '#ef4444',
          color: 'white',
          borderRadius: '8px',
          marginBottom: '1rem'
        }}>
          {exportStatus}
        </div>
      )}

      <GanttChart
        ref={ganttRef}
        tasks={tasks}
        darkMode={darkMode}
        onTaskUpdate={setTasks}
      />
    </div>
  );
}

⚔ Performance Optimization

React Modern Gantt is optimized for performance, especially in detailed views like Minute and Hour modes.

Minute View Optimization

To prevent performance issues with large timelines, the Minute View is automatically limited to 500 intervals. If your time range would generate more than 500 intervals, the component will:

  • āœ‚ļø Truncate the timeline to 500 intervals
  • āš ļø Show a console warning with optimization suggestions

Example:

// This would create ~2880 intervals (24 hours Ɨ 12 intervals/hour)
<GanttChart
  viewMode={ViewMode.MINUTE}
  minuteStep={5}
  startDate={new Date(2024, 0, 1, 0, 0)}
  endDate={new Date(2024, 0, 2, 0, 0)} // 24 hours later
/>
// → Console: "Minute view limited to 500 intervals for performance..."

Recommendations

  • For timelines > 40 hours: Use Hour View instead of Minute View
  • Increase minuteStep: Use 10 or 15 minute intervals for longer ranges
  • Use smaller time ranges: Keep Minute View for 1-2 days maximum
  • Switch view modes: Use Day/Week/Month views for long-term planning

Performance Metrics

MetricBefore OptimizationAfter OptimizationImprovement
Minute View (24h) DOM Elements~2,880Max 50083% reduction
Render Time~500ms~120ms76% faster
Scroll PerformanceLaggySmoothGreatly improved

Additional Optimizations

  • šŸŽÆ React.memo on Timeline component for reduced re-renders
  • šŸš€ RequestAnimationFrame for smooth scrolling and animations
  • šŸ“¦ Minimal DOM updates during drag operations

šŸŽØ Customization

CSS Variables

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;
}

Custom Styles

<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}
/>

Custom Rendering

<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>
  )}
/>

šŸŽÆ Event Handling

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

Dark mode is built-in and easy to enable:

<GanttChart tasks={tasks} darkMode={true} onTaskUpdate={handleTaskUpdate} />

šŸ”„ Advanced Examples

Custom Task Rendering by Status

<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',
    };
  }}
/>

Custom Tooltip for Detailed Information

<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>
  )}
/>

🌐 Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

ā“ FAQ

Can I change the date format in the timeline?

Yes, you can use the locale prop to change the date formatting:

<GanttChart
  tasks={tasks}
  locale="de-DE" // For German formatting
/>

How do I handle updates to tasks?

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
    )
  );
};

Can I make the Gantt chart read-only?

Yes, set the editMode prop to false:

<GanttChart tasks={tasks} editMode={false} />

This will disable ALL editing: task movement, resizing, and progress editing.

Can I disable specific editing features?

Yes! You have granular control over different editing features:

// Disable only progress editing (tasks still movable/resizable)
<GanttChart
  tasks={tasks}
  editMode={true}
  showProgress={true}
  allowProgressEdit={false}
/>

// Disable task resizing (can move, can't resize)
<GanttChart
  tasks={tasks}
  editMode={true}
  allowTaskResize={false}
/>

// Disable task movement (can resize, can't move)
<GanttChart
  tasks={tasks}
  editMode={true}
  allowTaskMove={false}
/>

// Enable ONLY progress editing (no task editing)
<GanttChart
  tasks={tasks}
  editMode={true}
  showProgress={true}
  allowTaskMove={false}
  allowTaskResize={false}
/>

How do I disable progress indicators?

Set the showProgress prop to false (it's false by default):

<GanttChart tasks={tasks} showProgress={false} />

To enable progress indicators, set it to true:

<GanttChart tasks={tasks} showProgress={true} editMode={true} />

Note: Progress bars are only editable when both editMode={true} AND showProgress={true}.

How do I enable Infinite Scroll?

Set infiniteScroll={true} and provide the onTimelineExtend callback:

const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(addMonths(new Date(), 6));

<GanttChart
  tasks={tasks}
  startDate={startDate}
  endDate={endDate}
  infiniteScroll={true}
  onTimelineExtend={(direction, newStart, newEnd) => {
    setStartDate(newStart);
    setEndDate(newEnd);
  }}
/>;

Why is my Minute View limited to 500 intervals?

For performance reasons, Minute View is automatically limited to 500 intervals. This prevents performance issues with large timelines. If you need to display longer time ranges:

  • Use a larger minuteStep (10 or 15 minutes instead of 5)
  • Switch to Hour View for timelines longer than ~40 hours
  • Break your timeline into smaller chunks

Can I customize the visual appearance of specific tasks?

Yes, use the getTaskColor function:

<GanttChart
  tasks={tasks}
  getTaskColor={({ task }) => ({
    backgroundColor: task.isUrgent ? '#ef4444' : '#3b82f6',
    textColor: 'white',
  })}
/>

Why are my styles not loading?

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.

šŸ¤ Contributing

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

šŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Keywords

react

FAQs

Package last updated on 25 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts