Skip to content

Link editing

The user draws a dependency from a round handle that appears at either end of a bar when it is hovered, and removes one from the menu that a click on its arrow opens. The chart reports each with onLinkCreate and onLinkDelete, tells you what it refused with onEditRefused, and changes nothing it should not: a link that would close a cycle, repeat one, or link a task to itself is never created.

Terminal window
pnpm add @ganttlane/dom # vanilla
pnpm add @ganttlane/react react react-dom # React
View on GitHub
data.ts
import type { Link, Task } from '@ganttlane/core';
// 2026-03-02 is a Monday. Docs and Review have no links yet: draw some.
export const tasks: Task[] = [
{ id: 'design', name: 'Design', start: '2026-03-02', end: '2026-03-06', progress: 100 },
{ id: 'api', name: 'API', start: '2026-03-09', end: '2026-03-13', progress: 60 },
{ id: 'ui', name: 'UI', start: '2026-03-09', end: '2026-03-17', progress: 30 },
{ id: 'docs', name: 'Docs', start: '2026-03-16', end: '2026-03-19' },
{ id: 'integrate', name: 'Integrate', start: '2026-03-18', end: '2026-03-24' },
{ id: 'qa', name: 'QA', start: '2026-03-25', end: '2026-03-27' },
{ id: 'review', name: 'Review', start: '2026-03-30', end: '2026-03-31' },
{ id: 'launch', name: 'Launch', type: 'milestone', start: '2026-04-01' },
];
export const links: Link[] = [
{ source: 'design', target: 'api' },
{ source: 'design', target: 'ui' },
{ source: 'api', target: 'integrate' },
{ source: 'ui', target: 'integrate' },
{ source: 'integrate', target: 'qa' },
// `editable: false`: the menu of this link does not offer to remove it (the click still selects).
{ source: 'qa', target: 'launch', editable: false },
];

Files

  • data.ts: eight tasks and six links; one link has editable: false.
  • options.ts: editing.links, the type of the links the user draws, the layout.
  • helpers.ts: the lines of the status, and the four link types.
  • vanilla.ts and react.tsx: the handlers, the checkbox for editing.links and the select for the type of new links.

Options

Option Value What it does
editing.links true, toggled by the box Draw links from the handles and remove them from the menu; false turns both off
scheduling.defaultLinkType 'FS', set by the select The type of a link the user draws: 'FS', 'SS', 'FF' or 'SF'
link.editable false on QA to Launch The menu of that link does not offer to remove it
onLinkCreate a function (in the example) (link, id): a link was drawn, or added by addLink
onLinkDelete a function (in the example) (record): a link was removed, from the menu or by removeLink
onLinkClick a function (in the example) (record, event): the arrow of a link was clicked; the link is now selected
onEditRefused a function (in the example) A link that was not drawn, with the reason
viewMode 'week' The scale of the timeline (React: defaultViewMode)
scroll.initial 'first-task' Opens on the plan
layout.rowHeight, .barHeight 36, 24 Smaller rows, so that every task is in view

What to try

  • Draw by dragging. Hover Docs: a round handle shows on each side of the bar. Press the one at the right end, drag onto QA and let go: Created Docs → QA (FS). Nothing moves; a link without a lag keeps the gap it has.
  • Draw by clicking twice. Click the handle (the link is now armed and follows the pointer), then click the target bar. Escape, a click on empty space or a click outside the chart cancels it.
  • Remove. Click the arrow of a link and choose Remove dependency. The arrow from QA to Launch has editable: false: it is selected, and its menu has nothing to offer.
  • Be refused. Draw a link from a bar onto itself (self), onto a task it already points at (duplicate), and from Launch back to Design (cycle: Design leads to Launch through the chain). Nothing is created, and the line under the chart says why.
  • Change the type. Pick SS in the select and draw another link: it is a start-to-start link, drawn from the start of the source to the start of the target. A link of another type between the same two tasks is not a duplicate.
  • Turn it off. Untick editing.links: the handles go and the links have no menu.

Notes

  • Both handles make the same link. The handle you press only says where the line starts; the type is scheduling.defaultLinkType ('FS' unless you set it), and the link is from the task you pressed on to the task you released on.
  • What onEditRefused says for links. { gesture: 'link-create', id, target, reason, at }: id is the source, reason is 'self', 'cycle', 'duplicate' or 'permission' (a task is linkable: false, or editing.links is off). While the pointer is over a target that would be refused the cursor is not-allowed, and the event comes on release.
  • The data is the chart’s own. The chart is uncontrolled here, so it appends the link to its links and removes it again by itself. If your state owns the links, take them from onLinkCreate and onLinkDelete (React: onLinksChange gives the whole list), as Controlled data does.
  • From code. addLink(link) and removeLink(id) run the same checks and, for addLink, the onBeforeLinkCreate hook, and return a result: see Programmatic updates and Before-hooks.
  • The menu is linkMenu: its render and its onRemove can be replaced, for a confirmation or your own buttons. By default onRemove is the chart’s own removeLink.
  • React. editing and scheduling are ordinary props, so the checkbox and the select are state. tasks, links and viewMode are the controlled ones: defaultTasks and defaultLinks are where the chart starts, and the links the user draws are then the chart’s own.