diff --git a/docs/how-to/define-nodes-edges.md b/docs/how-to/define-nodes-edges.md
index 6ab4882..ff329c7 100644
--- a/docs/how-to/define-nodes-edges.md
+++ b/docs/how-to/define-nodes-edges.md
@@ -155,11 +155,34 @@ edges = [
| `source` | yes | ID of the source node. |
| `target` | yes | ID of the target node. |
| `label` | no | Text rendered on the edge. |
-| `type` | no | Edge type name (for styling / editors). |
+| `type` | no | Edge type (see built-in types below, or a custom type name). |
| `data` | no | Arbitrary dict of payload data. |
| `sourceHandle` | no | Specific output handle on the source node. |
| `targetHandle` | no | Specific input handle on the target node. |
+### Built-in edge types
+
+| Type | Description |
+|------------------|-------------|
+| `"bezier"` | Smooth bezier curve (default). |
+| `"straight"` | Straight line between nodes. |
+| `"step"` | Orthogonal path with right angles. |
+| `"smoothstep"` | Step path with rounded corners. |
+| `"smart_bezier"` | Bezier curve that automatically routes around nodes. |
+| `"smart_straight"`| Straight segments that automatically route around nodes. |
+| `"smart_step"` | Step path that automatically routes around nodes. |
+
+Smart edge types use pathfinding to avoid overlapping with other nodes in
+the graph. They are useful when edges would otherwise pass through
+intermediate nodes.
+
+```python
+edges = [
+ {"id": "e1", "source": "n1", "target": "n2", "type": "smoothstep"},
+ {"id": "e2", "source": "n1", "target": "n3", "type": "smart_bezier"},
+]
+```
+
---
## Define edges as classes
diff --git a/examples/edge_types_comparison.py b/examples/edge_types_comparison.py
new file mode 100644
index 0000000..1cc4f92
--- /dev/null
+++ b/examples/edge_types_comparison.py
@@ -0,0 +1,102 @@
+"""
+Comparison of standard edges vs smart edges.
+
+This example demonstrates the difference between standard React Flow edges
+and smart edges that automatically route around obstacles.
+"""
+
+import panel as pn
+from panel_reactflow import EdgeSpec, NodeSpec, ReactFlow
+
+pn.extension()
+
+# Create nodes arranged to show edge routing
+nodes = [
+ # Left column - sources
+ NodeSpec(id="s1", position={"x": 0, "y": 0}, label="Source 1").to_dict(),
+ NodeSpec(id="s2", position={"x": 0, "y": 100}, label="Source 2").to_dict(),
+ NodeSpec(id="s3", position={"x": 0, "y": 200}, label="Source 3").to_dict(),
+ NodeSpec(id="s4", position={"x": 0, "y": 300}, label="Source 4").to_dict(),
+ # Middle obstacles
+ NodeSpec(id="obs1", position={"x": 150, "y": 50}, label="Obstacle 1").to_dict(),
+ NodeSpec(id="obs2", position={"x": 150, "y": 150}, label="Obstacle 2").to_dict(),
+ NodeSpec(id="obs3", position={"x": 150, "y": 250}, label="Obstacle 3").to_dict(),
+ # Right column - targets
+ NodeSpec(id="t1", position={"x": 300, "y": 0}, label="Target 1").to_dict(),
+ NodeSpec(id="t2", position={"x": 300, "y": 100}, label="Target 2").to_dict(),
+ NodeSpec(id="t3", position={"x": 300, "y": 200}, label="Target 3").to_dict(),
+ NodeSpec(id="t4", position={"x": 300, "y": 300}, label="Target 4").to_dict(),
+]
+
+# Create edges with different types
+edges = [
+ # Default edge (goes through obstacle)
+ EdgeSpec(
+ id="e1",
+ source="s1",
+ target="t2",
+ label="default",
+ type=None,
+ style={"stroke": "#999"},
+ ).to_dict(),
+ # Smart bezier (routes around obstacle)
+ EdgeSpec(
+ id="e2",
+ source="s2",
+ target="t3",
+ label="smart_bezier",
+ type="smart_bezier",
+ style={"stroke": "#3b82f6"},
+ ).to_dict(),
+ # Smart straight (routes around obstacle)
+ EdgeSpec(
+ id="e3",
+ source="s3",
+ target="t1",
+ label="smart_straight",
+ type="smart_straight",
+ style={"stroke": "#10b981"},
+ ).to_dict(),
+ # Smart step (routes around obstacle)
+ EdgeSpec(
+ id="e4",
+ source="s4",
+ target="t4",
+ label="smart_step",
+ type="smart_step",
+ style={"stroke": "#f59e0b"},
+ ).to_dict(),
+]
+
+# Create the flow
+flow = ReactFlow(
+ nodes=nodes,
+ edges=edges,
+ height=600,
+ width="100%",
+)
+
+# Layout
+pn.template.FastListTemplate(
+ title="Edge Types Comparison",
+ sidebar=[
+ pn.pane.Markdown(
+ """
+ ## Edge Types
+
+ This example compares different edge types:
+
+ - **Gray (default)**: Standard edge that goes straight through obstacles
+ - **Blue (smart_bezier)**: Curved edge that routes around obstacles
+ - **Green (smart_straight)**: Straight segments that avoid obstacles
+ - **Orange (smart_step)**: Step-style edge that avoids obstacles
+
+ ### Try it:
+ - Drag the obstacle nodes around
+ - Watch how smart edges automatically reroute
+ - Notice the default edge doesn't avoid obstacles
+ """,
+ ),
+ ],
+ main=[flow],
+).servable()
diff --git a/examples/smart_edges_example.py b/examples/smart_edges_example.py
new file mode 100644
index 0000000..0952e48
--- /dev/null
+++ b/examples/smart_edges_example.py
@@ -0,0 +1,99 @@
+"""
+Example demonstrating smart edges that automatically route around nodes.
+
+Smart edges automatically find paths around nodes to avoid overlaps.
+Available edge types:
+- 'bezier' (default): Smooth bezier curve
+- 'straight': Straight line between nodes
+- 'step': Orthogonal step path (right angles)
+- 'smoothstep': Step path with rounded corners
+- 'smart_bezier': Smart bezier curve that routes around nodes
+- 'smart_straight': Smart straight segments that route around nodes
+- 'smart_step': Smart step path that routes around nodes
+"""
+
+import panel as pn
+import panel_material_ui as pmui
+from panel_reactflow import EdgeSpec, NodeSpec, ReactFlow
+
+pn.extension()
+
+# Create a simple graph with nodes that would normally cause edge overlaps
+nodes = [
+ NodeSpec(id="1", position={"x": 0, "y": 100}, label="Start").to_dict(),
+ NodeSpec(id="2", position={"x": 200, "y": 0}, label="Top").to_dict(),
+ NodeSpec(id="3", position={"x": 200, "y": 200}, label="Bottom").to_dict(),
+ NodeSpec(id="4", position={"x": 400, "y": 100}, label="End").to_dict(),
+ NodeSpec(id="5", position={"x": 200, "y": 100}, label="Middle Obstacle").to_dict(),
+]
+
+# Create edges with different types
+edges = [
+ EdgeSpec(id="e1", source="1", target="4", label="Regular", type=None).to_dict(),
+ EdgeSpec(id="e2", source="2", target="3", label="Smart Bezier", type="smart_bezier").to_dict(),
+ EdgeSpec(id="e3", source="1", target="2", label="Smart Straight", type="smart_straight").to_dict(),
+ EdgeSpec(id="e4", source="1", target="3", label="Smart Step", type="smart_step").to_dict(),
+]
+
+# Create the flow with smart edges
+flow = ReactFlow(
+ nodes=nodes,
+ edges=edges,
+ sizing_mode="stretch_both"
+)
+
+# Create edge type selector
+edge_type_selector = pmui.Select(
+ label="Edge Type for e1",
+ options={
+ "Bezier (default)": "bezier",
+ "Straight": "straight",
+ "Step": "step",
+ "Smooth Step": "smoothstep",
+ "Smart Bezier": "smart_bezier",
+ "Smart Straight": "smart_straight",
+ "Smart Step": "smart_step",
+ },
+ value=None,
+)
+
+
+def update_edge_type(event):
+ """Update the edge type when selector changes."""
+ for edge in flow.edges:
+ edge["type"] = event.new
+ flow.edges = flow.edges # Trigger update
+
+edge_type_selector.param.watch(update_edge_type, "value")
+
+# Layout
+pmui.Page(
+ title="Smart Edges Example",
+ sidebar=[
+ pn.pane.Markdown(
+ """
+ ## Smart Edges Demo
+
+ Smart edges automatically route around nodes to avoid overlaps.
+
+ **Standard Edge Types:**
+ - **Bezier**: Smooth bezier curve (default)
+ - **Straight**: Direct straight line
+ - **Step**: Orthogonal path (right angles)
+ - **Smooth Step**: Step path with rounded corners
+
+ **Smart Edge Types:**
+ - **Smart Bezier**: Curved path that avoids nodes
+ - **Smart Straight**: Straight segments that route around nodes
+ - **Smart Step**: Step-style path that avoids nodes
+
+ **Try it:**
+ 1. Change the edge type for the "Start → End" connection
+ 2. Drag nodes around to see smart edges automatically reroute
+ 3. Notice how smart edges avoid the "Middle Obstacle" node
+ """,
+ ),
+ edge_type_selector,
+ ],
+ main=[flow],
+).servable()
diff --git a/src/panel_reactflow/base.py b/src/panel_reactflow/base.py
index 7ec105c..f28da76 100644
--- a/src/panel_reactflow/base.py
+++ b/src/panel_reactflow/base.py
@@ -687,7 +687,17 @@ class EdgeSpec:
label : str, optional
Display label shown on the edge. If ``None``, no label is displayed.
type : str, optional
- Edge type identifier. Reference a custom type defined in
+ Edge type identifier. Built-in types are:
+
+ - ``'bezier'`` (default): Smooth bezier curve
+ - ``'straight'``: Straight line between nodes
+ - ``'step'``: Orthogonal step path (right angles)
+ - ``'smoothstep'``: Step path with rounded corners
+ - ``'smart_bezier'``: Bezier curve that routes around nodes
+ - ``'smart_straight'``: Straight segments that route around nodes
+ - ``'smart_step'``: Step path that routes around nodes
+
+ You can also reference a custom type defined in
``ReactFlow.edge_types`` for schema validation and custom rendering.
selected : bool, default False
Whether the edge is currently selected in the UI.
@@ -1411,7 +1421,12 @@ class ReactFlow(ReactComponent):
_bundle = DIST_PATH / "panel-reactflow.bundle.js"
_esm = Path(__file__).parent / "models" / "reactflow.jsx"
- _importmap = {"imports": {"@xyflow/react": "https://esm.sh/@xyflow/react@12.8.3"}}
+ _importmap = {
+ "imports": {
+ "@xyflow/react": "https://esm.sh/@xyflow/react@12.8.3",
+ "@tisoap/react-flow-smart-edge": "https://esm.sh/@tisoap/react-flow-smart-edge@4.0.3",
+ }
+ }
_stylesheets = [DIST_PATH / "panel-reactflow.bundle.css", DIST_PATH / "css" / "reactflow.css"]
_render_policy = "manual"
diff --git a/src/panel_reactflow/models/reactflow.jsx b/src/panel_reactflow/models/reactflow.jsx
index dd2bc07..eef77eb 100644
--- a/src/panel_reactflow/models/reactflow.jsx
+++ b/src/panel_reactflow/models/reactflow.jsx
@@ -1,6 +1,7 @@
import React from "react";
-import { Background, Controls, Handle, MiniMap, NodeToolbar, Panel, Position, ReactFlow, ReactFlowProvider, addEdge, useEdgesState, useNodesState, useReactFlow, useStore } from "@xyflow/react";
+import { Background, BezierEdge, Controls, Handle, MiniMap, NodeToolbar, Panel, Position, ReactFlow, ReactFlowProvider, SmoothStepEdge, StraightEdge, StepEdge, addEdge, useEdgesState, useNodes, useNodesState, useReactFlow, useStore, BaseEdge, getBezierPath, getSmoothStepPath, getStraightPath } from "@xyflow/react";
import "@xyflow/react/dist/style.css";
+import { getSmartEdge, svgDrawStraightLinePath, pathfindingAStarNoDiagonal } from "@tisoap/react-flow-smart-edge";
const { useCallback, useEffect, useMemo, useRef, useState } = React;
@@ -179,6 +180,188 @@ function makeNodeComponent(typeName, typeSpec, editorMode) {
};
}
+function SmartBezierEdge(props) {
+ const {
+ id,
+ sourceX,
+ sourceY,
+ targetX,
+ targetY,
+ sourcePosition,
+ targetPosition,
+ style = {},
+ markerEnd,
+ label,
+ } = props;
+
+ const nodes = useNodes();
+
+ const getSmartEdgeResponse = getSmartEdge({
+ sourcePosition,
+ targetPosition,
+ sourceX,
+ sourceY,
+ targetX,
+ targetY,
+ nodes,
+ });
+
+ if (getSmartEdgeResponse instanceof Error) {
+ const [path, labelX, labelY] = getBezierPath({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition });
+ return (
+ <>
+