DEV Community

Cover image for How to Build a Gantt Chart for Web Apps with DHTMLX
Pavel Lazarev
Pavel Lazarev

Posted on

How to Build a Gantt Chart for Web Apps with DHTMLX

Adding a Gantt chart to a project management app can save developers from implementing task hierarchies, dependencies, timeline rendering, and scheduling logic themselves. In this guide, we'll build a basic Gantt chart with DHTMLX and gradually turn it into a more functional project planning interface.

We'll start with plain HTML, CSS, and JavaScript, then cover common features such as sorting, task reordering, inline editing, custom task colors, and auto scheduling. We'll also look at the official React, Angular, and Vue wrappers and some ways to use AI with DHTMLX Gantt.

Downloading and Installing DHTMLX Gantt

There are a few ways to add DHTMLX Gantt to a project. For a simple example, loading the component from the CDN is probably the quickest option.

Include the stylesheet and JavaScript file in your HTML page:

<link rel="stylesheet" type="text/css" href="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.css">
<script src="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.js"></script>
Enter fullscreen mode Exit fullscreen mode

With this approach, there is no need to configure a bundler or install additional dependencies. The library becomes available as soon as the page loads.

If you'd rather store the library with the rest of your application, you can download the package instead. DHTMLX Gantt is available in two editions for this purpose:

After downloading the package, unpack it and reference the files from the codebase folder:

<head>
   <script src="codebase/dhtmlxgantt.js"></script>
   <link href="codebase/dhtmlxgantt.css" rel="stylesheet">
</head>
Enter fullscreen mode Exit fullscreen mode

Initializing the Gantt Chart

The Gantt interface can live inside any regular HTML element. For this example, we'll use a div that takes up the entire browser window:

<body>
    <div id="gantt_here" style='width:100vw; height:100vh;'></div>
</body>
Enter fullscreen mode Exit fullscreen mode

The ID isn't tied to DHTMLX in any way, so feel free to replace gantt_here with something that makes sense for your application. Just use the same value when initializing the component.

window.addEventListener("DOMContentLoaded", function () {
    gantt.init("gantt_here");
});

Enter fullscreen mode Exit fullscreen mode

Once the DOM is available, gantt.init() creates the Gantt instance inside the specified container.

There aren't any tasks to display yet, so the chart will be empty. That's expected. Before adding more configuration, let's put some actual project information into it.

Adding Data to the Gantt Chart

For the demo, we'll keep the project data in the page and pass it to Gantt with gantt.parse(). In a production application, the data could of course come from a server or another data source.

Our sample project has two main stages:
1) Social Research Planning

  • Choosing Research Problems
  • Formulating Research Design 2) Conducting Research
  • Data Collection
  • Results Analysis

Each task contains the information needed to position it on the timeline and place it in the project hierarchy. We'll also use task priority and progress values, while a separate set of links defines the dependencies.

gantt.parse ({
    "data": [
        { "id": "10", "text": "Social Research Planning", "start_date": "01-04-2023", "duration": 5, "order": 10, "progress": 0.4, "open": true },
        { "id": "1", "text": "Choosing Research Problems", "start_date": "01-04-2023", "duration": 2, "order": 10, "progress": 0.6, "parent": "10", "priority": "high" },
        { "id": "2", "text": "Formulating Research Design", "start_date": "03-04-2023", "duration": 3, "order": 20, "progress": 0.6, "parent": "10", "priority": "high" },
        { "id": "20", "text": "Conducting Research", "start_date": "06-04-2023", "duration": 5, "order": 10, "progress": 0.4, "type": "project", "open": true },
        { "id": "3", "text": "Data Collection", "start_date": "06-04-2023", "duration": 2, "order": 10, "progress": 0.6, "parent": "20", "priority": "low" },
        { "id": "4", "text": "Results Analysis", "start_date": "08-04-2023", "duration": 3, "order": 20, "progress": 0.6, "parent": "20", "priority": "medium" }
    ],
    "links": [
        { "id": 1, "source": 1, "target": 2, "type": "0" },
        { "id": 2, "source": 2, "target": 3, "type": "0" },
        { "id": 3, "source": 3, "target": 4, "type": "0" },
        { "id": 4, "source": 2, "target": 5, "type": "0" }
    ]
})
Enter fullscreen mode Exit fullscreen mode

Gantt dataset

The parent field is responsible for the task hierarchy. For example, task 2 has parent: 1, so it appears underneath the "Social Research Planning" project. The same relationship puts tasks 5 and 6 under "Conducting Research."

Dependencies are stored in links. Each link points from one task to another using source and target. The type value specifies how those tasks are related.

The other task properties affect what appears in the chart. start_date and duration determine the task's position and length, progress controls its completion level, and priority gives us information that we can use later for custom styling.

Now that the chart contains a real project, we can start adding the interactions that users are likely to need when working with it.

Configuring Common Gantt Features

A project plan usually isn't something users only look at. They need to rearrange it, edit task information, find particular items, and understand important distinctions between tasks.

DHTMLX Gantt has configuration options, templates, methods, and events for these scenarios. The following examples show how several common requirements can be handled without building the corresponding functionality from scratch.

You can also see these features together in the HTML Gantt chart example.

Sorting Columns

As the number of tasks grows, users may want to organize the grid by a particular column rather than scan the rows manually.

Column sorting can be switched on with:

gantt.config.sort = true;
gantt.init("gantt_here");
Enter fullscreen mode Exit fullscreen mode

Column sorting in Gantt chart

After that, clicking a column header changes the sorting order.

There are situations where the application needs to initiate the sort itself. In those cases, the sort() method can be used from JavaScript. The [documentation] contains examples of programmatic sorting.

Reordering Tasks

Sorting only changes how information is presented. If users need to change the actual order of tasks in the project tree, they can do that with branch reordering.

The standard behavior is enabled as follows:

gantt.config.order_branch = true;
gantt.init("gantt_here");
Enter fullscreen mode Exit fullscreen mode

This lets users drag a task to another position at the same level of the hierarchy. The default behavior still respects the existing tree structure, so, for example, a child task cannot be moved to the position of one of its ancestors.

Some applications need to allow more freedom when restructuring a project. Setting order_branch_free to true allows tasks to move between different levels:

gantt.config.order_branch_free = true;
Enter fullscreen mode Exit fullscreen mode

There's another option worth knowing about when working with large datasets. Reordering a whole branch can involve a considerable amount of work as the number of tasks increases. The marker mode provides an alternative:

gantt.config.order_branch = "marker";
Enter fullscreen mode Exit fullscreen mode

The built-in behavior can also be supplemented with application-specific restrictions. For example, imagine that users should be able to reorder tasks but must not move them to another parent. The onBeforeTaskMove event can enforce that rule:

gantt.attachEvent("onBeforeTaskMove", function(id, parent, tindex){
    const task = gantt.getTask(id);
    if(task.parent != parent)
        return false;
    return true;
});
Enter fullscreen mode Exit fullscreen mode

The event receives the proposed parent ID, which can be compared with the task's current parent. Returning false stops the move when the hierarchy would otherwise change.

This approach is useful when the default drag-and-drop rules don't exactly match the rules of the application.

Customizing Task Colors

Sometimes the timeline needs to communicate more than dates and progress. A simple visual distinction can help users spot important tasks without reading every row.

Let's use the priority property from our data as an example. With the task_class template, we can assign a CSS class according to the task's priority:

<style>
    body,
    html {
        width: 100%;
        height: 100%;
        margin: unset;
    }

    .red_color {
        background: red;
    }

    .blue_color {
        background: blue;
    }

    .gray_color {
        background: gray;

    }

    .gantt_task_progress {
        background-color: rgba(33, 33, 33, 0.17);
    }
</style>
Enter fullscreen mode Exit fullscreen mode
gantt.templates.task_class = function (start, end, task) {
    switch (task.priority) {
        case "high":
             return 'red_color'
        case "medium":
             return 'blue_color'
        case "low":
             return 'gray_color'
    }
}
Enter fullscreen mode Exit fullscreen mode

custom colors for tasks

The template isn't limited to priority. Any task property can be used as the basis for the returned class. An application could use the same technique for status, category, team ownership, or another piece of project-specific information.

Inline Editing

Once users start maintaining the project in the Gantt chart, making small changes directly in the grid is often more convenient than sending them to a separate form.

DHTMLX Gantt has built-in editors for common values such as text, dates, and numbers. They can be assigned to grid columns through the column configuration:

gantt.config.columns = [
    {name: "text", tree: true, width: '*', resize: true, editor: textEditor},
    {name: "start_date", align: "center", resize: true, editor: dateEditor},
    {name: "duration", align: "center", editor: durationEditor},
    {name: "add", width: 44}
];
Enter fullscreen mode Exit fullscreen mode

Here, type determines which editor is used, while map_to connects that editor to a property in the task object.

The editor can also impose limits on the values. For example, a date editor can define the range of dates that users can select, while a number editor can specify minimum and maximum values:

const textEditor = { type: "text", map_to: "text" };
const dateEditor = {
    type: "date", map_to: "start_date", min: new Date(2023, 0, 1),
    max: new Date(2024, 0, 1)
};
const durationEditor = { type: "number", map_to: "duration", min: 0, max: 100 };
Enter fullscreen mode Exit fullscreen mode

Auto Scheduling

The previous examples change the way users work with the chart. Auto scheduling changes what happens to the schedule when those edits affect task relationships.

Suppose one task is connected to another through a dependency. If its dates move, manually updating every related task can become tedious. Auto scheduling allows Gantt to recalculate the affected dates based on the dependency structure.

The feature uses a plugin, so start by enabling auto_scheduling:

gantt.plugins({
    auto_scheduling: true
});
Enter fullscreen mode Exit fullscreen mode

Then enable it in the configuration:

gantt.config.auto_scheduling = true;

With both settings in place, Gantt can automatically recalculate task dates according to their dependencies and scheduling constraints.

The JavaScript Gantt example with time constraints provides a working example of this behavior.

Auto scheduling is available only in the PRO edition of DHTMLX Gantt.

Using DHTMLX Gantt with React, Angular, and Vue

The plain JavaScript example is useful for understanding the component itself, but many applications don't use JavaScript components in isolation. If the rest of the application is written in React, Angular, or Vue, Gantt also needs to fit into that environment.

One possibility is to integrate the JavaScript component directly. This gives you control over the integration, but you also need to connect the Gantt instance to the framework yourself. That can include initialization, lifecycle handling, updates, and cleanup.

The official DHTMLX wrappers provide a framework-specific alternative for React, Angular, and Vue.

Rather than replacing the underlying Gantt component, the wrappers make it easier to incorporate it into an application that already follows one of these frameworks' conventions. At the same time, developers can continue working with the functionality provided by the JavaScript Gantt component.

This means you don't have to choose a completely different Gantt implementation just because the surrounding application uses a framework. The same component can be integrated through the appropriate wrapper.

Exploring AI-Assisted Development with DHTMLX Gantt

AI coding assistants are increasingly being used for everyday development tasks, from generating initial code to explaining APIs and helping debug an implementation. For component libraries, though, the quality of the result depends heavily on the information available to the assistant.

An AI model may know that a Gantt chart needs tasks and dependencies, for example, without knowing the recommended way to configure a particular Gantt library. Giving the assistant current, library-specific context can make a difference.

DHTMLX provides several resources for this purpose. Developers working with Claude Code, Cursor, or Gemini CLI can use the official DHTMLX MCP server to access current DHTMLX documentation and examples. DHTMLX also offers agent skills for DHTMLX Gantt integrations with JavaScript, React, and Angular.

These resources are aimed at AI-assisted development rather than replacing the developer's role. They give coding assistants additional DHTMLX-specific context when generating or modifying an integration.

There's another side to the AI story as well. Instead of using AI only while writing the application, developers can make AI part of the application itself.

Several experimental DHTMLX Gantt demos illustrate this idea:

The three examples demonstrate different ways of combining Gantt with AI. AI can help generate a configuration, customize the chart's appearance, or provide a different way of working with project information.

For developers experimenting with AI-powered project management applications, these approaches can serve as starting points for exploring what can be built around a Gantt component.

Wrapping Up

A Gantt chart can involve quite a bit of functionality once it becomes part of an actual project management application. Beyond displaying tasks on a timeline, the component may need to handle hierarchies, dependencies, editing, reordering, visual customization, and schedule calculations.

DHTMLX Gantt provides these capabilities through its JavaScript API, while the official wrappers make the component easier to incorporate into React, Angular, and Vue applications.

There are also several ways to experiment with AI around Gantt. AI assistants can work with DHTMLX-specific development resources, while AI-powered features can be added directly to applications built with the component.


The article was originally published in the DHTMLX blog.

Top comments (0)