Skip to content

Auto-connect on handle drag ​

When the user drags from a node handle and drops on another node, @flowgl/core does not add the edge automatically — it just emits a connect event with the resolved source / target / handles. This is on purpose: most apps want to validate or transform before committing.

The minimal "always accept" pattern:

ts
import { FlowChart, generateId } from '@flowgl/core'

const chart = new FlowChart({ container, nodes, edges })

chart.on('connect', ({ sourceId, targetId, sourceHandle, targetHandle }) => {
  chart.addEdge({
    id: generateId('e'),
    source: sourceId,
    target: targetId,
    sourceHandle,
    targetHandle,
  })
})

generateId('e') returns 'e-<8 hex chars>'. Use crypto.randomUUID() or your own id factory if you need globally unique ids for a backend.

Rejecting connections before they're created ​

onBeforeConnect lets you return false to drop the connection before the connect event ever fires. Use it for validation rules that should read like the type system, not like a handler.

ts
new FlowChart({
  container,
  nodes,
  edges,
  onBeforeConnect: ({ sourceId, targetId, sourceHandle, targetHandle }) => {
    // No self-connections
    if (sourceId === targetId) return false
    // Already connected? No duplicates.
    if (chart.getEdgesBetween(sourceId, targetId).length > 0) return false
    // Port that allows only 1 inbound
    if (targetHandle === 'in' && chart.getEdgesForNode(targetId)
        .filter(e => e.target === targetId && e.targetHandle === 'in').length >= 1) {
      return false
    }
    return true
  },
})

When onBeforeConnect returns false, the user sees the drag snap back visually and no event fires. No edge is created.

Adding edge metadata at creation time ​

The connect event payload is exactly what the source-target gesture resolved — no styling, no label, no domain data. Add anything you need during addEdge:

ts
chart.on('connect', ({ sourceId, targetId, sourceHandle, targetHandle }) => {
  const src = chart.getNode(sourceId)
  const tgt = chart.getNode(targetId)

  chart.addEdge({
    id: generateId('e'),
    source: sourceId,
    target: targetId,
    sourceHandle,
    targetHandle,
    // Domain metadata
    label: `${src?.label} → ${tgt?.label}`,
    animated: src?.type === 'stream',
    style: {
      width: 2,
      color: '#6366f1',
      dashArray: src?.type === 'optional' ? [8, 4] : undefined,
    },
  })
})

Mirroring the new edge back to your app's state ​

If you're driving the chart from React / Vue / Svelte / Redux / Zustand / Pinia, the connect handler is the right place to push the new edge into your store. The wrapper components do this internally already — see the Wire to state store recipe for the pattern.

See also ​

Released under the MIT License.