When building modern React apps for project management, teams are often asked to implement advanced scheduling functionalities that remain responsive as datasets grow. To help achieve this goal, DHTMLX offers the React Gantt component as a powerful foundation for a scheduling UI, which is also compatible with the Remix framework that delivers data to the UI more efficiently via server-side loading. In this blog post, we’ll explore the basics of integrating our React Gantt with this full-stack JavaScript framework using the official react-gantt-remix-starter demo as a practical reference.
What Remix Brings to a React Gantt App
Previously, we discussed the benefits of integrating comprehensive UI components with SSR frameworks on the example of our React Gantt and Next.js. Using Remix, we approach the same full-stack React space via a more explicit, React Router-based architecture. The framework leans heavily on web-standard APIs rather than abstractions, thereby contributing to more predictable data flows and routing behavior.
This straightforward approach can be a valid option for data-intensive UIs with Gantt charts, scheduling calendars, or dashboards, where active interactions on the frontend often demand routing, persistence, and server communication.
In our starter demo, however, we deliberately focused on the rendering flow. It emphasizes the following aspects:
- Route-driven data flow
- Configuration object stabilization
- Gantt UI changes
- Access to the Gantt API
Other Remix-related concepts like loaders, actions, and data persistence are not covered in the demo. Our main objective here is to show that React Gantt matches well with the Remix rendering approach without delving into the backend architecture details.
Starting from v9.0.12, our React Gantt component supports SSR frameworks (Next.js and Remix) without extra configuration. This means that you don’t need to use any special client-only wrappers to use the component in SSR environments.
Integration Insights
Now it is time to elaborate on the key integration points of DHTMLX React Gantt with Remix, listed in the section above.
- Rendering the Gantt chart inside the Remix route
In this demo, the Gantt chart is implemented inside the dedicated GanttChart component. Then, the chart is mounted directly inside a standard Remix route component without any extra SSR handling. You just import the component and pass data to it:
import type { Route } from './+types/home';
import { tasks, links } from '~/data/demoData';
export default function Home() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<GanttChart tasks={tasks} links={links} />
</div>
);
}
The route is responsible for the app structure and data flow, while the Gantt component primarily focuses on rendering and user interactions with the UI. Tasks and links are passed into the chart as props, while UI edits are emitted via the save function discussed below.
The demo uses a local dataset, but the same setup can later be connected to server-loaded data using special Remix loaders.
The chart also requires a parent container with the specified height (width: ‘100vw’, height: ‘100vh’). Otherwise, the Gantt chart may be displayed incorrectly even with the proper component mounting inside the route.
- Stabilizing the Gantt configuration
The GanttConfig object declares how the Gantt chart is structured and displayed through configuration options for dates, scale, controls, etc. If this object is recreated on every render cycle, the Gantt will reinitialize, which is absolutely unnecessary. That is why we wrapped the config in the React hook called 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' },
],
}),
[]
);
By applying this memoization approach, we ensure that the Gantt configuration is created once and reused during the lifetime of the component.
- Enabling updates processing via the data.save callback
When end-users interact with the Gantt chart, or more precisely, edit tasks or dependency links, these changes are reported via the data.save callback:
save: (entity: string, action: string, data: Task | Link, id: string | number) => {
console.log(`${entity} - ${action} - ${id}`, data);
},
}}
In our demo project, data.save only logs the changes. For real-world scenarios, this is exactly where you would call a Remix action function or bind these changes to the React state. Learn more about data binding options in the documentation.
- Ensuring access to the underlying Gantt API
Finally, we would like to mention that our demo includes a reference to the Gantt instance with the useRef hook:
const gantt = ganttRef.current?.instance;
if (!gantt) return;
// here you can call ANY Gantt API method
console.log('All tasks:', gantt.getTaskByTime());
gantt.showDate(new Date());
Thus, you get direct access to the underlying Gantt API for imperative chart operations without triggering re-renders. This option may not be needed for basic setups, but it will certainly simplify future API-driven customizations when needed.
With a clear understanding of these points, you will hardly have any doubts or confusion when working with the react-gantt-remix-starter repository and integration guide.
Closing Thoughts
The Remix starter demo is another building block at your disposal for creating modern project management apps with DHTMLX React Gantt. It covers the basics of bridging the gap between the frontend, based on advanced UI components, and a full-stack architecture. Following the demo approach and the associated documentation guide, you can create a foundational template that is extensible with specific persistence and state management strategies required for a given project.