DEV Community

Cover image for 🎃 Create a Halloween-Themed Gantt Chart with SVAR React Gantt
Olga T.
Olga T.

Posted on • Originally published at svar.dev

🎃 Create a Halloween-Themed Gantt Chart with SVAR React Gantt

This Halloween I invite you to create something both functional and fun! In this tutorial, we’ll build a Halloween-themed task manager using SVAR React Gantt, a powerful, open-source project management component that can easily handle serious enterprise workloads… but today, we’re giving it a spooky twist.

The demo app will track the ultimate October project — organizing a Halloween party. You’ll plan tasks, set dates, and assign responsibilities, so you can later know who’s to blame if the candy runs out 😝

You’ll learn how to use SVAR React Gantt to:

  • Add a Gantt chart and fill it with data
  • Customize the task editor
  • Add a context menu and tooltips
  • Customize the default theme

And while it’s fun to play with pumpkins and ghosts, everything here translates directly to production-grade project management apps.

Useful links:

  • Online demo: see the Halloween-styled Gantt chart demo
  • Demo package: download the demo package
  • GitHub: find the source code of SVAR React Gantt

Including Sources

We start by installing SVAR Gantt Chart source files via npm:

npm install @svar-ui/react-gantt
Enter fullscreen mode Exit fullscreen mode

Adding Gantt Chart on a Page

Import SVAR Gantt, the CSS styles, and the desired theme. The task manager comes with light and dark skins: Willow and WillowDark. To give the chart a spooky styling, in our tutorial we’ll use WillowDark theme as a basis.

Component.jsx

import { Gantt, WillowDark } from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";
Enter fullscreen mode Exit fullscreen mode

Add the Gantt on page and define a theme for it:

Component.jsx

import { Gantt, WillowDark } from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";

function Component() {
  return (
    <WillowDark>
      <Gantt />
    </WillowDark>
  );
}
export default Component;
Enter fullscreen mode Exit fullscreen mode

Filling Gantt Chart with Data

To bring our task manager to life, we need to provide the initial data for tasks and their links that form the project's structure at the initialization stage. The data includes four key elements: scales (timeline units), tasks (project activities with dates and progress), links (dependencies between tasks), and users (assignees for tasks).

data/index.js

const dayStyle = (date) => {
  const day = date.getDay() === 5 || date.getDay() === 6;
  return day ? 'sday' : '';
};

export const scales = [
  { unit: 'month', step: 1, format: 'MMMM yyy' },
  { unit: 'day', step: 1, format: 'd', css: dayStyle },
];

export const tasks = [
  {
    id: 1,
    start: new Date(2025, 9, 19),
    end: new Date(2025, 9, 25),
    text: 'Planning & Preparation',
    progress: 100,
    parent: 0,
    type: 'summary',
    open: true,
    details: '',
  },
  {
    id: 11,
    start: new Date(2025, 9, 19),
    end: new Date(2025, 9, 20),
    text: 'Set date',
    progress: 100,
    parent: 1,
    type: 'task',
    details:
      "Finalize the date and time for the Halloween party. Make sure it suits everyone's availability",
    to: 1,
  },
  // ... Other task data
];

export const links = [
  {
    id: 1,
    source: 11,
    target: 13,
    type: 'e2s',
  },
  // ... Other link data
];

export const users = [
  { id: 1, label: 'David' },
  { id: 2, label: 'Olivia' },
];

export function getData() {
  return { tasks, links, scales, users };
}
Enter fullscreen mode Exit fullscreen mode

Since we keep our data on client side in a separate file, we need to import it and pass the corresponding data items to the Gantt component as props:

Component.jsx

import { useMemo, useState } from 'react';
import { Gantt, WillowDark } from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";
import { getData } from '../data';

function Component() {
  const [api, setApi] = useState();

  const data = useMemo(() => getData(), []);

  return (
    <WillowDark>
      <Gantt 
        init={setApi}
        tasks={data.tasks} 
        links={data.links}
        scales={data.scales}
      />
    </WillowDark>
  );
}

export default Component;
Enter fullscreen mode Exit fullscreen mode

For more information about preparing and loading data, refer to the following documentation section: Loading data.

Customizing Task Tree

The Gantt widget includes a left-hand panel that displays a task tree, providing users with an overview of project details. By default, this tree features four columns: Task Name, Start Date, Duration, and Action. While this layout provides detailed insights, it can also take up extra screen space, which is especially valuable in busy project views.

To create a more compact interface, we can adjust the task tree structure using the columns property. If we exclude the default Duration column, we can free up space on the screen, allowing for a cleaner view that keeps the focus on the most critical information: task name, start date, and the + button to add a new task.

SVAR React Gantt - Task Tree

Component.jsx

import { useMemo, useState } from 'react';
import { Gantt, WillowDark } from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";
import { getData } from '../data';

function Component() {
  const [api, setApi] = useState();

  const data = useMemo(() => getData(), []);

  // Define the new structure of the Task Tree
  const columns = [
    { id: 'text', header: 'Task name', width: 210 },
    {
      id: 'start',
      header: 'Start date',
      width: 106,
      align: 'center',
    },
    { id: 'add-task', header: '', width: 40, align: 'center' },
  ];

  return (
    <WillowDark>
      <Gantt 
        init={setApi}
        tasks={data.tasks} 
        links={data.links}
        scales={data.scales}
        columns={columns}
      />
    </WillowDark>
  );
}

export default Component;
Enter fullscreen mode Exit fullscreen mode

Adding Task Editor

The default editor of the Gantt chart provides a straightforward way for users to edit tasks and save changes directly on the chart. However, for our Halloween-themed project tracker, we'll enhance the standard editor by adding a custom field to assign responsibilities to each task.

React Gantt Chart - Task Edit Form

Component.jsx

import { useMemo, useState } from 'react';
import { 
  Gantt, 
  WillowDark,
  Editor,
  defaultEditorItems // Import the default settings of the Gantt editor
} from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";
import { getData } from '../data';

function Component() {
  const [api, setApi] = useState();

  const data = useMemo(() => getData(), []);

  const columns = [
    { id: 'text', header: 'Task name', width: 210 },
    {
      id: 'start',
      header: 'Start date',
      width: 106,
      align: 'center',
    },
    { id: 'add-task', header: '', width: 40, align: 'center' },
  ];

  // Reshape the default editor settings to exclude unnecessary fields
  const editorItems = defaultEditorItems.filter(
    (op) => op.key !== 'duration' && op.key !== 'links'
  );

  // Add a custom field to assign the responsible user
  editorItems.splice(3, 0, {
    key: 'to',
    type: 'select',
    label: 'Goes to',
    options: data.users,
    config: { placeholder: 'Select the person' },
    comp: 'select',
  });

  return (
    <WillowDark>
      <Gantt 
        init={setApi}
        tasks={data.tasks} 
        links={data.links}
        scales={data.scales}
        columns={columns}
      />
      {api && <Editor api={api} autoSave={false} items={editorItems} />}
    </WillowDark>
  );
}

export default Component;
Enter fullscreen mode Exit fullscreen mode

For more information about configuring the task editor, refer to the following documentation section: Configuring task editor.

Adding Context Menu

SVAR Gantt component uses ContextMenu component as a context menu. The menu can be packed with a wide range of options for managing tasks: editing, deleting, creating subtasks, and much more. While this full menu offers extensive functionality, our Halloween Gantt app requires a more compact, streamlined set of options to keep the interface clean and focused.

SVAR React Gantt - Context Menu

Let's customize the context menu and select only the essential options that suit our demo app's needs.

Component.jsx

import { useMemo, useState } from 'react';
import { 
  Gantt, 
  WillowDark,
  Editor,
  ContextMenu, // Import the built-in context menu
  defaultMenuOptions, // Import default menu options
  defaultEditorItems
} from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";
import { getData } from '../data';

function Component() {
  const [api, setApi] = useState();

  const data = useMemo(() => getData(), []);

  const columns = [
    { id: 'text', header: 'Task name', width: 210 },
    {
      id: 'start',
      header: 'Start date',
      width: 106,
      align: 'center',
    },
    { id: 'add-task', header: '', width: 40, align: 'center' },
  ];

  const editorItems = defaultEditorItems.filter(
    (op) => op.key !== 'duration' && op.key !== 'links'
  );
  editorItems.splice(3, 0, {
    key: 'to',
    type: 'select',
    label: 'Goes to',
    options: data.users,
    config: { placeholder: 'Select the person' },
    comp: 'select',
  });

  // Specify a set of available options within a custom context menu
  const ids = ['add-task', 'edit-task', 'delete-task', 'move-task'];

  // Reshape the default menu options considering the custom options
  const options = defaultMenuOptions.filter((op) => ids.indexOf(op.id) >= 0);

  return (
    <WillowDark>
      <ContextMenu api={api} options={options}>
        <Gantt 
          init={setApi}
          tasks={data.tasks} 
          links={data.links}
          scales={data.scales}
          columns={columns}
        />
      </ContextMenu>
      {api && <Editor api={api} autoSave={false} items={editorItems} />}
    </WillowDark>
  );
}

export default Component;
Enter fullscreen mode Exit fullscreen mode

Please note that to activate the context menu features, you need to access Gantt API and pass it to the <ContextMenu api={api}> component. In this case we use the init prop to capture the API reference when Gantt initializes.

For more information on how to configure the context menu, refer to the following documentation section: Configuring the context menu.

Adding Tooltips

By default, the SVAR Gantt chart doesn't show tooltips. But we can easily activate this feature. All we need is to import the Tooltip component and wrap our Gantt component with it. Do not forget to provide the API reference as with the ContextMenu.

This simple setup will allow users to hover the pointer over a task or project and see a tooltip with the task's info.

Component.jsx

import { useMemo, useState } from 'react';
import { 
  Gantt, 
  WillowDark,
  Editor,
  ContextMenu,
  Tooltip, // Import the built-in tooltip
  defaultMenuOptions,
  defaultEditorItems
} from "@svar-ui/react-gantt";
import "@svar-ui/react-gantt/all.css";
import { getData } from '../data';

function Component() {
  const [api, setApi] = useState();

  const data = useMemo(() => getData(), []);

  const columns = [
    { id: 'text', header: 'Task name', width: 210 },
    {
      id: 'start',
      header: 'Start date',
      width: 106,
      align: 'center',
    },
    { id: 'add-task', header: '', width: 40, align: 'center' },
  ];

  const editorItems = defaultEditorItems.filter(
    (op) => op.key !== 'duration' && op.key !== 'links'
  );
  editorItems.splice(3, 0, {
    key: 'to',
    type: 'select',
    label: 'Goes to',
    options: data.users,
    config: { placeholder: 'Select the person' },
    comp: 'select',
  });

  const ids = ['add-task', 'edit-task', 'delete-task', 'move-task'];
  const options = defaultMenuOptions.filter((op) => ids.indexOf(op.id) >= 0);

  return (
    <WillowDark>
      <ContextMenu api={api} options={options}>
        <Tooltip api={api}>
          <Gantt 
            init={setApi}
            tasks={data.tasks} 
            links={data.links}
            scales={data.scales}
            columns={columns}
          />
        </Tooltip>
      </ContextMenu>
      {api && <Editor api={api} autoSave={false} items={editorItems} />}
    </WillowDark>
  );
}

export default Component;
Enter fullscreen mode Exit fullscreen mode

For our Halloween-themed app, though, a simple title won't capture the full story. To make task details more accessible and engaging, we'll create a custom tooltip that displays the task description and assigned user.

SVAR React Gantt - Tooltips

First of all, we need to create a custom template for a tooltip. For convenience, we can put it in a separate file.

TooltipContent.jsx

import { users } from '../data'; // Import data for USERS to be displayed in a tooltip

export default function TooltipContent({ data }) {
  if (!data) return null;

  const { to, details } = data;

  return (
    <>
      {to || details ? (
        <div className="data">
          {details ? ( // Create a view for details (if exist)
            <div className="text">
              <span className="caption">🎃 Description: </span>
              <span className="details">{details}</span>
            </div>
          ) : null}
          {to ? ( // Create a view for assignee (if exists)
            <div className="text">
              <span className="caption">👻 Goes to: </span>
              {users.find((u) => u.id === to)?.label}
            </div>
          ) : null}
        </div>
      ) : null}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

TooltipContent.css

.data {
  background-color: #2b343b;
  padding: 8px 12px;
  width: 260px;
}

.text {
  width: 100%;
  height: fit-content;
  font-family: var(--wx-font-family);
  color: #ffffff;
  text-transform: capitalize;
  font-size: 14px;
  line-height: 20px;
}

.text + .text {
  margin-top: 8px;
}

.text:last-child {
  margin-bottom: 0;
}

.details {
  word-wrap: break-word;
}

.caption {
  font-weight: 600;
}
Enter fullscreen mode Exit fullscreen mode

After the tooltip template is ready, we can import and apply it via the Tooltip content property.

Component.jsx

import TooltipContent from './TooltipContent';
import './TooltipContent.css';

// ...
  <Tooltip api={api} content={TooltipContent}>
    <Gantt 
      init={setApi}
      tasks={data.tasks} 
      links={data.links}
      scales={data.scales}
      columns={columns}
    />
  </Tooltip>
// ...
Enter fullscreen mode Exit fullscreen mode

For more information about configuring tooltips, refer to the following documentation section: Adding tooltips.

Tuning Look and Feel

When initializing the project, we applied the WillowDark skin, which provides a clean and elegant design. However, to truly capture the essence of Halloween, we need to go beyond the basics and incorporate custom styles that resonate with the season's spirit. The key customizations include a dark background, purple task bars, orange summary tasks, and lime green dependency links for that perfect Halloween vibe.

To change the default theme settings, create a separate CSS file with custom CSS variables and apply it to the Halloween Gantt app.

This is how we replace colors in Component.css (excerpt):

.content {
  --wx-background: #161616;
  --wx-color-primary: #3c2369;
  --wx-color-danger: #eb691f;

  --wx-gantt-summary-color: #ee8c1d;
  --wx-gantt-summary-fill-color: #eb691f;

  --wx-gantt-task-color: #3c2369;
  --wx-gantt-task-fill-color: #582c8f;

  --wx-gantt-link-color: #9ee41f;
  /* Other custom variables */
}

.content .wx-bar.wx-milestone .wx-content {
  background: url('/assets/pumpkin.svg') no-repeat center / cover;
}
Enter fullscreen mode Exit fullscreen mode

Apply the styles by wrapping your component in a container with the content class:

Demo.jsx

import { WillowDark } from '@svar-ui/react-gantt';
import Component from './components/Component';
import './Component.css';

function Demo() {
  return (
    <div className="demo">
      <WillowDark />
      <div className="content wx-willow-dark-theme">
        <Component />
      </div>
    </div>
  );
}

export default Demo;
Enter fullscreen mode Exit fullscreen mode

You can find the complete list of rules in the related demo.

Summing Up

With these tweaks, our Halloween task manager is ready to bring order (and a little mischief) to the seasonal chaos.

We’ve customized tooltips, streamlined the context menu, added user assignments, and wrapped everything in a festive theme, all powered by SVAR React Gantt!

If you enjoy working with SVAR React Gantt, we’d really appreciate your ⭐ on GitHub. It helps us grow and keep improving the component.

Top comments (0)