Project Management Integrations for MUI Apps
Gantt charts, Kanban boards, scheduling, and resource management libraries
that compose with MUI's theme, layout, and component slots.
MUI X does not ship a native Gantt component (roadmap item, not yet available).
Use these libraries for the timeline and MUI for everything around it.
Gantt Chart Libraries
SVAR React Gantt — Best Free Option (MIT)
npm install wx-react-gantt
Free MIT core:
- Interactive drag-and-drop task editing on timeline
- Task dependencies (FS, SS, EE, SE)
- Hierarchical/summary tasks with collapsible groups
- Customizable task bars, tooltips, grid columns, time scale
- Multiple zoom levels, keyboard navigation, light/dark themes
- Full TypeScript, React 19 compatible, Vite/Next.js
- 10,000+ task performance
SVAR PRO (~$524/dev perpetual) adds:
- Working-day calendars per project/task/resource
- Baselines (original plan vs current)
- Auto-scheduling (tasks shift when dependencies change)
- Split tasks, undo/redo, rollups, slack visualization
- Export to PDF, PNG, Excel
- Import/export MS Project files
MUI integration:
import { Gantt } from 'wx-react-gantt';
import Paper from '@mui/material/Paper';
import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
function ProjectGantt({ tasks, links }) {
const [editTask, setEditTask] = useState(null);
return (
<Paper sx={{ height: 600, overflow: 'hidden' }}>
{/* MUI toolbar above Gantt */}
<Box sx={{ display: 'flex', gap: 1, p: 1, borderBottom: 1, borderColor: 'divider' }}>
<Button size="small" In</Button>
<Button size="small" Out</Button>
<DateRangePicker slotProps={{ textField: { size: 'small' } }} />
</Box>
{/* Gantt handles timeline rendering */}
<Gantt
tasks={tasks}
links={links}
=> setEditTask(task)}
/>
{/* MUI Dialog for task editing */}
<Dialog open={!!editTask} => setEditTask(null)} maxWidth="sm" fullWidth>
<TaskEditForm task={editTask} />
</Dialog>
</Paper>
);
}
DHTMLX React Gantt — Enterprise (Paid)
npm install @dhx/react-gantt
- Renders 30,000+ tasks smoothly
- Auto-scheduling, critical path calculation
- Resource management with histogram (PRO)
- Working time calendars at project/task/resource levels
- Undo/redo with Valtio or Redux
- Official MUI examples in docs using MUI Button, Divider, ButtonGroup, icons
- Standard: free (limited); PRO: ~$699/dev; Team: ~$1,299
Bryntum Gantt — MS Project Feature Parity (Paid)
- MS Project-equivalent scheduling engine (ChronoGraph)
- Critical path with early/late dates, free slack, total slack
- Baselines: any number of snapshots
- Progress line visualization
- Resource assignment column with multi-select picker
- CSS variables align to MUI theme tokens
- ~$680-940/dev perpetual
- SaaS/OEM requires separate license — contact before committing
Syncfusion React Gantt — Free for Small Teams
- Free Community License for <$1M revenue, ≤5 devs, ≤10 employees
- Critical path with
enableCriticalPath prop
- Resource view, filtering, split tasks, undo/redo
- Part of 1,900+ component suite
- Export PDF/CSV/Excel
FullCalendar Premium — Resource Scheduling ($480/dev/yr)
- Free MIT: day/week/month calendar, drag-and-drop
- Premium: Resource Timeline (horizontal, Gantt-like), Vertical Resource view
- Best for contractor availability/booking views, not dependency Gantt
Feature Comparison Matrix
| Feature |
SVAR Free |
SVAR PRO |
DHTMLX PRO |
Bryntum |
Syncfusion Community |
| Cost |
Free MIT |
~$524/dev |
~$699/dev |
~$680/dev |
Free (<$1M) |
| React native |
✓ |
✓ |
✓ |
Wrapper |
Wrapper |
| Drag/drop |
✓ |
✓ |
✓ |
✓ |
✓ |
| Dependencies |
✓ |
✓ |
✓ |
✓ |
✓ |
| Critical path |
— |
— |
✓ |
✓ |
✓ |
| Baselines |
— |
✓ |
✓ |
✓ |
✓ |
| Auto-scheduling |
— |
✓ |
✓ |
✓ |
✓ |
| Resource mgmt |
— |
— |
✓ |
✓ |
✓ |
| Working calendars |
— |
✓ |
✓ |
✓ |
✓ |
| MS Project import |
— |
✓ |
— |
— |
— |
| Export PDF/Excel |
— |
✓ |
✓ |
✓ |
✓ |
| Undo/redo |
— |
✓ |
✓ |
✓ |
✓ |
| MUI theming |
✓ |
✓ |
✓ documented |
✓ |
CSS vars |
| SaaS/OEM allowed |
✓ MIT |
✓ |
✓ |
Need OEM |
Needs paid |
| Max tasks |
10K+ |
10K+ |
30K+ |
30K+ |
Large |
Kanban Board Libraries
dnd-kit — Modern Standard (MIT Free)
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
The successor to react-beautiful-dnd. Community standard for React DnD.
import {
DndContext,
DragOverlay,
closestCorners,
PointerSensor,
KeyboardSensor,
useSensor,
useSensors,
} from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import Paper from '@mui/material/Paper';
import Card from '@mui/material/Card';
import Typography from '@mui/material/Typography';
import Avatar from '@mui/material/Avatar';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
// Sortable card using MUI Card
function KanbanCard({ task }: { task: Task }) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: task.id,
});
const style = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.5 : 1,
};
return (
<Card
ref={setNodeRef}
style={style}
{...attributes}
{...listeners}
sx={{
p: 1.5, mb: 1, cursor: 'grab',
'&:hover': { borderColor: 'primary.main', boxShadow: 2 },
border: '1px solid', borderColor: 'divider', borderRadius: 2,
}}
>
<Typography variant="body2" fontWeight={600}>{task.title}</Typography>
<Stack direction="row" spacing={1} sx={{ mt: 1 }} alignItems="center">
<Chip label={task.priority} size="small" color={priorityColor(task.priority)} />
<Avatar src={task.assignee.avatar} sx={{ width: 24, height: 24 }} />
</Stack>
</Card>
);
}
// Kanban column
function KanbanColumn({ column, tasks }: { column: Column; tasks: Task[] }) {
return (
<Paper
sx={{
width: 280, minHeight: 400, p: 1, borderRadius: 2,
bgcolor: 'action.hover',
}}
>
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mb: 1, px: 1 }}>
<Typography variant="subtitle2">{column.title}</Typography>
<Chip label={tasks.length} size="small" />
</Stack>
<SortableContext items={tasks.map((t) => t.id)} strategy={verticalListSortingStrategy}>
{tasks.map((task) => (
<KanbanCard key={task.id} task={task} />
))}
</SortableContext>
</Paper>
);
}
// Board with drag between columns
function KanbanBoard({ columns, tasks }: KanbanBoardProps) {
const sensors = useSensors(
useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
useSensor(KeyboardSensor),
);
const [activeId, setActiveId] = useState<string | null>(null);
return (
<DndContext
sensors={sensors}
collisionDetection={closestCorners}
active }) => setActiveId(active.id as string)}
>
<Stack direction="row" spacing={2} sx={{ overflowX: 'auto', p: 2 }}>
{columns.map((col) => (
<KanbanColumn
key={col.id}
column={col}
tasks={tasks.filter((t) => t.columnId === col.id)}
/>
))}
</Stack>
{/* Ghost clone while dragging */}
<DragOverlay>
{activeId && (
<Card sx={{ p: 1.5, boxShadow: 8, borderRadius: 2, opacity: 0.9 }}>
<Typography variant="body2">{findTask(activeId)?.title}</Typography>
</Card>
)}
</DragOverlay>
</DndContext>
);
}
Pattern: Intercept onDragEnd to call ASP.NET Core PATCH endpoint for column/order change. Use DragOverlay with MUI elevation for smooth animated ghost.
react-mui-scheduler — MUI-Native Calendar (MIT Free)
npm install react-mui-scheduler
- Month/week/day/timeline views built on
@mui/material
- Event grouping by resource
- Search bar, date picker, view switcher in toolbar
- Localization: 8 languages
- Best for appointment/availability calendars (contractor scheduling, event booking)
Pragmatic Drag and Drop (Atlassian) — MIT Free
npm install @atlaskit/pragmatic-drag-and-drop
- Powers Jira and Trello's drag-and-drop
- Lower-level API than dnd-kit, purpose-built for production kanban at scale
- MIT open-source since 2024
Recommended Stack by Use Case
| Use Case |
Library |
License |
| Contractor project timeline (internal) |
SVAR Gantt Free |
MIT |
| Full MS Project-equivalent Gantt in SaaS |
Bryntum OEM or DHTMLX PRO |
Paid |
| Free Gantt for early SaaS <$1M revenue |
Syncfusion Community |
Free |
| Resource booking / availability calendar |
FullCalendar Premium + MUI |
$480/yr |
| Kanban task board (Jira-style) |
dnd-kit + MUI Cards |
MIT |
| Contractor appointment scheduler |
react-mui-scheduler |
MIT |
| Flexible timeline (bookings, media) |
gantt-schedule-timeline-calendar |
Freemium |
Architecture: Gantt + MUI DataGrid Sidebar
The most powerful project management UI combines a Gantt timeline with a companion DataGrid.
┌─────────────────────────────────────────────────────────┐
│ MUI AppBar Toolbar │
│ [Zoom In] [Zoom Out] [View: Gantt|Kanban|Calendar] │
│ [DateRangePicker] [Export] │
├───────────────────────┬─────────────────────────────────┤
│ MUI X DataGrid │ Gantt Timeline (SVAR/DHTMLX) │
│ ┌─────────────────┐ │ ┌─────────────────────────────┐│
│ │ Task | Status │ │ │ ▓▓▓▓▓▓░░░ Project Alpha ││
│ │ Alpha| ● Active │◄─┼──│ ▓▓▓▓░░░░░ Task 1 ││
│ │ Beta | ○ Draft │ │ │ ▓▓▓▓▓░░ Task 2 ──────►││
│ │ Gamma| ● Active │ │ │ ▓▓▓ Task 3 ││
│ └─────────────────┘ │ └─────────────────────────────┘│
├───────────────────────┴─────────────────────────────────┤
│ MUI Drawer (right) — Task Detail Form │
│ [RHF Form] [Resource Autocomplete] [Time Entry Grid] │
└─────────────────────────────────────────────────────────┘
Implementation:
- Left panel: MUI X DataGrid with status chips, assignee avatars, priority bars
- Right panel: Gantt timeline synchronized to DataGrid selection
- Sync: Click DataGrid row → scroll Gantt to task; click Gantt bar → select DataGrid row
- Detail drawer: MUI Drawer with RHF form, resource Autocomplete, sub-DataGrid of time entries
- Toolbar: MUI GridToolbarContainer with zoom controls, view switches, DateRangePicker
function ProjectManagementView({ tasks, links }) {
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
const [drawerOpen, setDrawerOpen] = useState(false);
const ganttRef = useRef<GanttAPI>(null);
const gridApiRef = useGridApiRef();
// Sync: DataGrid row click → Gantt scroll
const handleGridRowClick = useCallback((params: GridRowParams) => {
setSelectedTaskId(params.id as string);
ganttRef.current?.scrollToTask(params.id);
}, []);
// Sync: Gantt bar click → DataGrid selection
const handleGanttTaskClick = useCallback((task: Task) => {
setSelectedTaskId(task.id);
gridApiRef.current?.selectRow(task.id);
gridApiRef.current?.scrollToIndexes({ rowIndex: findRowIndex(task.id) });
}, []);
return (
<Box sx={{ display: 'flex', height: 'calc(100vh - 64px)' }}>
{/* Left: DataGrid */}
<Box sx={{ width: 400, borderRight: 1, borderColor: 'divider' }}>
<DataGrid
apiRef={gridApiRef}
rows={tasks}
columns={taskColumns}
rowSelectionModel={selectedTaskId ? [selectedTaskId] : []}
/>
</Box>
{/* Right: Gantt */}
<Box sx={{ flex: 1 }}>
<Gantt
ref={ganttRef}
tasks={tasks}
links={links}
=> { setSelectedTaskId(task.id); setDrawerOpen(true); }}
/>
</Box>
{/* Detail Drawer */}
<Drawer
anchor="right"
open={drawerOpen}
=> setDrawerOpen(false)}
PaperProps={{ sx: { width: 480 } }}
>
{selectedTaskId && (
<TaskDetailForm
taskId={selectedTaskId}
=> { refetchTasks(); setDrawerOpen(false); }}
/>
)}
</Drawer>
</Box>
);
}
The Gantt library handles only timeline rendering and dependency logic.
MUI handles all surrounding UI — dialogs, forms, notifications, navigation, theming, and data tables.
Result: unified, branded experience matching your design system.
1---
2name: project-management-integrations
3description: Gantt charts, Kanban boards, scheduling, and resource management libraries that integrate with MUI — SVAR, DHTMLX, Bryntum, Syncfusion, FullCalendar, dnd-kit, and architecture patterns
4triggers:
5 - Gantt chart
6 - Kanban board
7 - project management
8 - scheduling
9 - resource management
10 - timeline
11 - drag and drop
12 - dnd-kit
13 - SVAR Gantt
14 - DHTMLX
15 - Bryntum
16 - Syncfusion
17 - FullCalendar
18 - task board
19 - contractor scheduling
20allowed-tools:
21 - Read
22 - Glob
23 - Grep
24 - Write
25 - Edit
26globs:
27 - "*.tsx"
28 - "*.ts"
29---
30
31# Project Management Integrations for MUI Apps
32
33Gantt charts, Kanban boards, scheduling, and resource management libraries
34that compose with MUI's theme, layout, and component slots.
35
36MUI X does not ship a native Gantt component (roadmap item, not yet available).
37Use these libraries for the timeline and MUI for everything around it.
38
39---
40
41## Gantt Chart Libraries
42
43### SVAR React Gantt — Best Free Option (MIT)
44
45```bash
46npm install wx-react-gantt
47```
48
49**Free MIT core:**
50- Interactive drag-and-drop task editing on timeline
51- Task dependencies (FS, SS, EE, SE)
52- Hierarchical/summary tasks with collapsible groups
53- Customizable task bars, tooltips, grid columns, time scale
54- Multiple zoom levels, keyboard navigation, light/dark themes
55- Full TypeScript, React 19 compatible, Vite/Next.js
56- 10,000+ task performance
57
58**SVAR PRO (~$524/dev perpetual) adds:**
59- Working-day calendars per project/task/resource
60- Baselines (original plan vs current)
61- Auto-scheduling (tasks shift when dependencies change)
62- Split tasks, undo/redo, rollups, slack visualization
63- Export to PDF, PNG, Excel
64- Import/export MS Project files
65
66**MUI integration:**
67```tsx
68import { Gantt } from 'wx-react-gantt';
69import Paper from '@mui/material/Paper';
70import Button from '@mui/material/Button';
71import Dialog from '@mui/material/Dialog';
72
73function ProjectGantt({ tasks, links }) {
74 const [editTask, setEditTask] = useState(null);
75
76 return (
77 <Paper sx={{ height: 600, overflow: 'hidden' }}>
78 {/* MUI toolbar above Gantt */}
79 <Box sx={{ display: 'flex', gap: 1, p: 1, borderBottom: 1, borderColor: 'divider' }}>
80 <Button size="small" onClick={handleZoomIn}>Zoom In</Button>
81 <Button size="small" onClick={handleZoomOut}>Zoom Out</Button>
82 <DateRangePicker slotProps={{ textField: { size: 'small' } }} />
83 </Box>
84
85 {/* Gantt handles timeline rendering */}
86 <Gantt
87 tasks={tasks}
88 links={links}
89 onTaskDblClick={(task) => setEditTask(task)}
90 />
91
92 {/* MUI Dialog for task editing */}
93 <Dialog open={!!editTask} onClose={() => setEditTask(null)} maxWidth="sm" fullWidth>
94 <TaskEditForm task={editTask} onSave={handleSave} />
95 </Dialog>
96 </Paper>
97 );
98}
99```
100
101### DHTMLX React Gantt — Enterprise (Paid)
102
103```bash
104npm install @dhx/react-gantt
105```
106
107- Renders 30,000+ tasks smoothly
108- Auto-scheduling, critical path calculation
109- Resource management with histogram (PRO)
110- Working time calendars at project/task/resource levels
111- Undo/redo with Valtio or Redux
112- **Official MUI examples** in docs using MUI Button, Divider, ButtonGroup, icons
113- Standard: free (limited); PRO: ~$699/dev; Team: ~$1,299
114
115### Bryntum Gantt — MS Project Feature Parity (Paid)
116
117- MS Project-equivalent scheduling engine (ChronoGraph)
118- Critical path with early/late dates, free slack, total slack
119- Baselines: any number of snapshots
120- Progress line visualization
121- Resource assignment column with multi-select picker
122- CSS variables align to MUI theme tokens
123- ~$680-940/dev perpetual
124- **SaaS/OEM requires separate license** — contact before committing
125
126### Syncfusion React Gantt — Free for Small Teams
127
128- **Free Community License** for <$1M revenue, ≤5 devs, ≤10 employees
129- Critical path with `enableCriticalPath` prop
130- Resource view, filtering, split tasks, undo/redo
131- Part of 1,900+ component suite
132- Export PDF/CSV/Excel
133
134### FullCalendar Premium — Resource Scheduling ($480/dev/yr)
135
136- Free MIT: day/week/month calendar, drag-and-drop
137- Premium: Resource Timeline (horizontal, Gantt-like), Vertical Resource view
138- Best for contractor availability/booking views, not dependency Gantt
139
140---
141
142## Feature Comparison Matrix
143
144| Feature | SVAR Free | SVAR PRO | DHTMLX PRO | Bryntum | Syncfusion Community |
145|---------|:---------:|:--------:|:----------:|:-------:|:--------------------:|
146| **Cost** | Free MIT | ~$524/dev | ~$699/dev | ~$680/dev | Free (<$1M) |
147| **React native** | ✓ | ✓ | ✓ | Wrapper | Wrapper |
148| **Drag/drop** | ✓ | ✓ | ✓ | ✓ | ✓ |
149| **Dependencies** | ✓ | ✓ | ✓ | ✓ | ✓ |
150| **Critical path** | — | — | ✓ | ✓ | ✓ |
151| **Baselines** | — | ✓ | ✓ | ✓ | ✓ |
152| **Auto-scheduling** | — | ✓ | ✓ | ✓ | ✓ |
153| **Resource mgmt** | — | — | ✓ | ✓ | ✓ |
154| **Working calendars** | — | ✓ | ✓ | ✓ | ✓ |
155| **MS Project import** | — | ✓ | — | — | — |
156| **Export PDF/Excel** | — | ✓ | ✓ | ✓ | ✓ |
157| **Undo/redo** | — | ✓ | ✓ | ✓ | ✓ |
158| **MUI theming** | ✓ | ✓ | ✓ documented | ✓ | CSS vars |
159| **SaaS/OEM allowed** | ✓ MIT | ✓ | ✓ | Need OEM | Needs paid |
160| **Max tasks** | 10K+ | 10K+ | 30K+ | 30K+ | Large |
161
162---
163
164## Kanban Board Libraries
165
166### dnd-kit — Modern Standard (MIT Free)
167
168```bash
169npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
170```
171
172The successor to `react-beautiful-dnd`. Community standard for React DnD.
173
174```tsx
175import {
176 DndContext,
177 DragOverlay,
178 closestCorners,
179 PointerSensor,
180 KeyboardSensor,
181 useSensor,
182 useSensors,
183} from '@dnd-kit/core';
184import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
185import { useSortable } from '@dnd-kit/sortable';
186import { CSS } from '@dnd-kit/utilities';
187import Paper from '@mui/material/Paper';
188import Card from '@mui/material/Card';
189import Typography from '@mui/material/Typography';
190import Avatar from '@mui/material/Avatar';
191import Chip from '@mui/material/Chip';
192import Stack from '@mui/material/Stack';
193
194// Sortable card using MUI Card
195function KanbanCard({ task }: { task: Task }) {
196 const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
197 id: task.id,
198 });
199
200 const style = {
201 transform: CSS.Transform.toString(transform),
202 transition,
203 opacity: isDragging ? 0.5 : 1,
204 };
205
206 return (
207 <Card
208 ref={setNodeRef}
209 style={style}
210 {...attributes}
211 {...listeners}
212 sx={{
213 p: 1.5, mb: 1, cursor: 'grab',
214 '&:hover': { borderColor: 'primary.main', boxShadow: 2 },
215 border: '1px solid', borderColor: 'divider', borderRadius: 2,
216 }}
217 >
218 <Typography variant="body2" fontWeight={600}>{task.title}</Typography>
219 <Stack direction="row" spacing={1} sx={{ mt: 1 }} alignItems="center">
220 <Chip label={task.priority} size="small" color={priorityColor(task.priority)} />
221 <Avatar src={task.assignee.avatar} sx={{ width: 24, height: 24 }} />
222 </Stack>
223 </Card>
224 );
225}
226
227// Kanban column
228function KanbanColumn({ column, tasks }: { column: Column; tasks: Task[] }) {
229 return (
230 <Paper
231 sx={{
232 width: 280, minHeight: 400, p: 1, borderRadius: 2,
233 bgcolor: 'action.hover',
234 }}
235 >
236 <Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mb: 1, px: 1 }}>
237 <Typography variant="subtitle2">{column.title}</Typography>
238 <Chip label={tasks.length} size="small" />
239 </Stack>
240
241 <SortableContext items={tasks.map((t) => t.id)} strategy={verticalListSortingStrategy}>
242 {tasks.map((task) => (
243 <KanbanCard key={task.id} task={task} />
244 ))}
245 </SortableContext>
246 </Paper>
247 );
248}
249
250// Board with drag between columns
251function KanbanBoard({ columns, tasks }: KanbanBoardProps) {
252 const sensors = useSensors(
253 useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
254 useSensor(KeyboardSensor),
255 );
256
257 const [activeId, setActiveId] = useState<string | null>(null);
258
259 return (
260 <DndContext
261 sensors={sensors}
262 collisionDetection={closestCorners}
263 onDragStart={({ active }) => setActiveId(active.id as string)}
264 onDragEnd={handleDragEnd}
265 onDragOver={handleDragOver}
266 >
267 <Stack direction="row" spacing={2} sx={{ overflowX: 'auto', p: 2 }}>
268 {columns.map((col) => (
269 <KanbanColumn
270 key={col.id}
271 column={col}
272 tasks={tasks.filter((t) => t.columnId === col.id)}
273 />
274 ))}
275 </Stack>
276
277 {/* Ghost clone while dragging */}
278 <DragOverlay>
279 {activeId && (
280 <Card sx={{ p: 1.5, boxShadow: 8, borderRadius: 2, opacity: 0.9 }}>
281 <Typography variant="body2">{findTask(activeId)?.title}</Typography>
282 </Card>
283 )}
284 </DragOverlay>
285 </DndContext>
286 );
287}
288```
289
290**Pattern:** Intercept `onDragEnd` to call ASP.NET Core PATCH endpoint for column/order change. Use `DragOverlay` with MUI elevation for smooth animated ghost.
291
292### react-mui-scheduler — MUI-Native Calendar (MIT Free)
293
294```bash
295npm install react-mui-scheduler
296```
297
298- Month/week/day/timeline views built on `@mui/material`
299- Event grouping by resource
300- Search bar, date picker, view switcher in toolbar
301- Localization: 8 languages
302- Best for appointment/availability calendars (contractor scheduling, event booking)
303
304### Pragmatic Drag and Drop (Atlassian) — MIT Free
305
306```bash
307npm install @atlaskit/pragmatic-drag-and-drop
308```
309
310- Powers Jira and Trello's drag-and-drop
311- Lower-level API than dnd-kit, purpose-built for production kanban at scale
312- MIT open-source since 2024
313
314---
315
316## Recommended Stack by Use Case
317
318| Use Case | Library | License |
319|----------|---------|---------|
320| Contractor project timeline (internal) | SVAR Gantt Free | MIT |
321| Full MS Project-equivalent Gantt in SaaS | Bryntum OEM or DHTMLX PRO | Paid |
322| Free Gantt for early SaaS <$1M revenue | Syncfusion Community | Free |
323| Resource booking / availability calendar | FullCalendar Premium + MUI | $480/yr |
324| Kanban task board (Jira-style) | dnd-kit + MUI Cards | MIT |
325| Contractor appointment scheduler | react-mui-scheduler | MIT |
326| Flexible timeline (bookings, media) | gantt-schedule-timeline-calendar | Freemium |
327
328---
329
330## Architecture: Gantt + MUI DataGrid Sidebar
331
332The most powerful project management UI combines a Gantt timeline with a companion DataGrid.
333
334```
335┌─────────────────────────────────────────────────────────┐
336│ MUI AppBar Toolbar │
337│ [Zoom In] [Zoom Out] [View: Gantt|Kanban|Calendar] │
338│ [DateRangePicker] [Export] │
339├───────────────────────┬─────────────────────────────────┤
340│ MUI X DataGrid │ Gantt Timeline (SVAR/DHTMLX) │
341│ ┌─────────────────┐ │ ┌─────────────────────────────┐│
342│ │ Task | Status │ │ │ ▓▓▓▓▓▓░░░ Project Alpha ││
343│ │ Alpha| ● Active │◄─┼──│ ▓▓▓▓░░░░░ Task 1 ││
344│ │ Beta | ○ Draft │ │ │ ▓▓▓▓▓░░ Task 2 ──────►││
345│ │ Gamma| ● Active │ │ │ ▓▓▓ Task 3 ││
346│ └─────────────────┘ │ └─────────────────────────────┘│
347├───────────────────────┴─────────────────────────────────┤
348│ MUI Drawer (right) — Task Detail Form │
349│ [RHF Form] [Resource Autocomplete] [Time Entry Grid] │
350└─────────────────────────────────────────────────────────┘
351```
352
353**Implementation:**
354
3551. **Left panel:** MUI X DataGrid with status chips, assignee avatars, priority bars
3562. **Right panel:** Gantt timeline synchronized to DataGrid selection
3573. **Sync:** Click DataGrid row → scroll Gantt to task; click Gantt bar → select DataGrid row
3584. **Detail drawer:** MUI Drawer with RHF form, resource Autocomplete, sub-DataGrid of time entries
3595. **Toolbar:** MUI GridToolbarContainer with zoom controls, view switches, DateRangePicker
360
361```tsx
362function ProjectManagementView({ tasks, links }) {
363 const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
364 const [drawerOpen, setDrawerOpen] = useState(false);
365 const ganttRef = useRef<GanttAPI>(null);
366 const gridApiRef = useGridApiRef();
367
368 // Sync: DataGrid row click → Gantt scroll
369 const handleGridRowClick = useCallback((params: GridRowParams) => {
370 setSelectedTaskId(params.id as string);
371 ganttRef.current?.scrollToTask(params.id);
372 }, []);
373
374 // Sync: Gantt bar click → DataGrid selection
375 const handleGanttTaskClick = useCallback((task: Task) => {
376 setSelectedTaskId(task.id);
377 gridApiRef.current?.selectRow(task.id);
378 gridApiRef.current?.scrollToIndexes({ rowIndex: findRowIndex(task.id) });
379 }, []);
380
381 return (
382 <Box sx={{ display: 'flex', height: 'calc(100vh - 64px)' }}>
383 {/* Left: DataGrid */}
384 <Box sx={{ width: 400, borderRight: 1, borderColor: 'divider' }}>
385 <DataGrid
386 apiRef={gridApiRef}
387 rows={tasks}
388 columns={taskColumns}
389 onRowClick={handleGridRowClick}
390 rowSelectionModel={selectedTaskId ? [selectedTaskId] : []}
391 />
392 </Box>
393
394 {/* Right: Gantt */}
395 <Box sx={{ flex: 1 }}>
396 <Gantt
397 ref={ganttRef}
398 tasks={tasks}
399 links={links}
400 onTaskClick={handleGanttTaskClick}
401 onTaskDblClick={(task) => { setSelectedTaskId(task.id); setDrawerOpen(true); }}
402 />
403 </Box>
404
405 {/* Detail Drawer */}
406 <Drawer
407 anchor="right"
408 open={drawerOpen}
409 onClose={() => setDrawerOpen(false)}
410 PaperProps={{ sx: { width: 480 } }}
411 >
412 {selectedTaskId && (
413 <TaskDetailForm
414 taskId={selectedTaskId}
415 onSave={() => { refetchTasks(); setDrawerOpen(false); }}
416 />
417 )}
418 </Drawer>
419 </Box>
420 );
421}
422```
423
424The Gantt library handles only timeline rendering and dependency logic.
425MUI handles all surrounding UI — dialogs, forms, notifications, navigation, theming, and data tables.
426Result: unified, branded experience matching your design system.