Skip to main content
SVAR Gantt ships three companion menu components — <Toolbar>, <ContextMenu>, and <HeaderMenu> — that all connect to the Gantt through the shared api prop.

Toolbar

<Toolbar> renders a row of action buttons above (or anywhere around) the chart.

Basic setup

1

Capture the API from Gantt

import { useState } from 'react';
import { Gantt, Toolbar } from '@svar-ui/react-gantt';

const [api, setApi] = useState();
2

Pass the API to Toolbar

<Toolbar api={api} />
<Gantt init={setApi} tasks={tasks} scales={scales} />
The toolbar renders default buttons (add task, indent/outdent, move up/down, delete, undo/redo when enabled) and automatically disables buttons that require a selection when nothing is selected.

Default toolbar buttons

Call getToolbarButtons() to retrieve the default button descriptors. Each button has an id that maps directly to a Gantt action name.
import { getToolbarButtons } from '@svar-ui/react-gantt';

// All buttons, including optional undo/split-task buttons:
const all = getToolbarButtons({ undo: true, splitTasks: true });

// Default set (no undo, no split):
const defaults = getToolbarButtons();
Button idAction triggered
add-taskadd-task
indent-taskindent-task
outdent-taskoutdent-task
move-task:upmove-task (mode: up)
move-task:downmove-task (mode: down)
delete-taskdelete-task
undoundo
redoredo

Customising toolbar buttons

Filter out unwanted buttons, add your own, and pass the result as the items prop.
import { Toolbar, getToolbarButtons } from '@svar-ui/react-gantt';

const items = [
  // Keep all default buttons except indent/outdent.
  ...getToolbarButtons().filter((b) => !b.id?.includes('indent')),
  // Add a custom button with its own handler.
  {
    id: 'my-action',
    comp: 'icon',
    icon: 'wxi-star',
    handler: () => console.log('custom action'),
  },
];

<Toolbar api={api} items={items} />

Fully custom toolbar

For full control, skip <Toolbar> entirely and build your own toolbar with standard React state and api.exec(). Subscribe to the reactive state store to track selection changes:
import { useState, useEffect } from 'react';
import { Gantt } from '@svar-ui/react-gantt';

function MyToolbar({ api }) {
  const [selected, setSelected] = useState([]);

  useEffect(() => {
    if (!api) return;
    const unsub = api.getReactiveState().selected.subscribe((v) => {
      setSelected(v ?? []);
    });
    return () => unsub?.();
  }, [api]);

  function handleAdd() {
    api.exec('add-task', {
      task: { text: 'New task' },
      target: selected[0],
      mode: 'after',
    });
  }

  function handleDelete() {
    selected.forEach((id) => api.exec('delete-task', { id }));
  }

  return (
    <div>
      <button onClick={handleAdd}>Add task</button>
      {selected.length > 0 && (
        <button onClick={handleDelete}>Delete task</button>
      )}
    </div>
  );
}

Context menu

<ContextMenu> wraps the <Gantt> as a child and shows a right-click menu on task rows.

Basic setup

import { Gantt, ContextMenu, Editor } from '@svar-ui/react-gantt';

<ContextMenu api={api}>
  <Gantt init={setApi} tasks={tasks} scales={scales} />
</ContextMenu>
{api && <Editor api={api} />}
The default menu includes add above/below/child, cut/copy/paste, and delete options.

Default menu options

import { getMenuOptions } from '@svar-ui/react-gantt';

const defaults = getMenuOptions();
Common option id values you can reference:
idDescription
add-task:beforeAdd task above
add-task:afterAdd task below
add-task:childAdd child task
cut-taskCut task
copy-taskCopy task
paste-taskPaste task
delete-taskDelete task

Customising menu options

Pass a custom options array to replace the defaults. Mix default options (looked up by id) with your own:
import { ContextMenu, getMenuOptions } from '@svar-ui/react-gantt';

const builtins = getMenuOptions();
const keepIds = ['cut-task', 'copy-task', 'paste-task', 'delete-task'];

const options = [
  { id: 'add-task:after', text: 'Add below', icon: 'wxi-plus' },
  ...builtins.filter((op) => keepIds.includes(op.id)),
  {
    id: 'my-action',
    text: 'My action',
    icon: 'wxi-star',
    handler: (action) => console.log('custom', action),
  },
];

function handleClick({ context, action }) {
  if (!action.handler) {
    console.log(`'${action.id}' clicked for task '${context.id}'`);
  }
}

<ContextMenu api={api} options={options} onClick={handleClick}>
  <Gantt init={setApi} tasks={tasks} scales={scales} />
</ContextMenu>

Filtering menu items per task

Use the filter prop to show or hide menu items based on the right-clicked task:
<ContextMenu
  api={api}
  filter={(option, task) => {
    // Hide "add child" for milestones.
    if (task.type === 'milestone') {
      const [base, mode] = (option.id ?? '').split(':');
      if (base === 'add-task' && mode === 'child') return false;
    }
    return true;
  }}
>
  <Gantt init={setApi} tasks={tasks} scales={scales} />
</ContextMenu>
The resolver prop controls which tasks trigger the menu. Return false to suppress the menu for a given task id:
<ContextMenu
  api={api}
  resolver={(id) => id > 2} // Only show menu for tasks with id > 2.
>
  ...
</ContextMenu>

HeaderMenu

<HeaderMenu> wraps the Gantt (or any grid-based widget) and adds a right-click menu on column headers for toggling column visibility.
import { Gantt, HeaderMenu } from '@svar-ui/react-gantt';

<HeaderMenu api={api}>
  <Gantt init={setApi} tasks={tasks} scales={scales} />
</HeaderMenu>
Pass a columns array to control which columns appear in the visibility toggle list:
<HeaderMenu
  api={api}
  columns={[
    { id: 'text',     header: 'Name' },
    { id: 'start',   header: 'Start' },
    { id: 'duration', header: 'Duration' },
  ]}
>
  <Gantt init={setApi} tasks={tasks} scales={scales} />
</HeaderMenu>

Intercepting actions (onaction)

All toolbar and context menu built-in actions route through api.exec(). You can intercept them before they execute using api.intercept():
const init = (api) => {
  setApi(api);

  // Block delete when a condition is not met.
  api.intercept('delete-task', ({ id }) => {
    const task = api.getTask(id);
    if (task.locked) {
      alert('This task cannot be deleted.');
      return false; // Returning false cancels the action.
    }
  });
};
See Event Handling for a full reference to api.intercept(), api.on(), and api.exec().

Props reference

Toolbar

PropTypeDefaultDescription
apiIApinullGantt API instance.
itemsarray[]Button descriptors. Falls back to getToolbarButtons() when empty.

ContextMenu

PropTypeDefaultDescription
apiIApinullGantt API instance.
optionsarray[]Menu item descriptors. Falls back to getMenuOptions() when empty.
resolverfunctionnull(id, ev) => task | boolean — controls which tasks get a menu.
filterfunctionnull(item, task) => boolean — per-task menu item visibility.
onClickfunction({ context, action }) => void — called when a menu item is clicked.
atstring'point'Positioning strategy for the menu popup.

HeaderMenu

PropTypeDefaultDescription
apiIApiGantt API instance used to resolve the table API.
columnsarraynullColumn descriptors to display in the visibility toggle.

Build docs developers (and LLMs) love