Skip to main content

Custom smart edges

Create a custom edge and call getSmartEdge for path computation.

Required inputs

  • sourcePosition, targetPosition, sourceX, sourceY, targetX, targetY — same as custom edge props
  • nodes — from useNodes

Example with a button label

Like React Flow's edge with button example:

import { useNodes, BezierEdge } from "@xyflow/react";
import { getSmartEdge } from "@tisoap/react-flow-smart-edge";
import type { EdgeProps } from "@xyflow/react";

const foreignObjectSize = 200;

export function SmartEdgeWithButtonLabel(props: EdgeProps) {
const {
id,
sourcePosition,
targetPosition,
sourceX,
sourceY,
targetX,
targetY,
style,
markerStart,
markerEnd,
} = props;

const nodes = useNodes();

const smartResponse = getSmartEdge({
sourcePosition,
targetPosition,
sourceX,
sourceY,
targetX,
targetY,
nodes,
});

if (smartResponse instanceof Error) {
return <BezierEdge {...props} />;
}

const { edgeCenterX, edgeCenterY, svgPathString } = smartResponse;

return (
<>
<path
style={style}
className="react-flow__edge-path"
d={svgPathString}
markerEnd={markerEnd}
markerStart={markerStart}
/>
<foreignObject
width={foreignObjectSize}
height={foreignObjectSize}
x={edgeCenterX - foreignObjectSize / 2}
y={edgeCenterY - foreignObjectSize / 2}
requiredExtensions="http://www.w3.org/1999/xhtml"
>
<button
type="button"
onClick={(event) => {
event.stopPropagation();
alert(`remove ${id}`);
}}
>
X
</button>
</foreignObject>
</>
);
}

Advanced configuration

Pass an optional options object to tune pathfinding. See Options and getSmartEdge.

const result = getSmartEdge({
sourcePosition,
targetPosition,
sourceX,
sourceY,
targetX,
targetY,
nodes,
options: {
nodePadding: 20,
gridRatio: 15,
},
});

Use smartEdgePresets to match built-in edge behavior:

import { getSmartEdge, smartEdgePresets } from "@tisoap/react-flow-smart-edge";

const bezierResult = getSmartEdge({ /* ... */, options: smartEdgePresets.bezier });
const stepResult = getSmartEdge({ /* ... */, options: smartEdgePresets.step });