Every edge type, including floating edges that attach to the nearest border.

Edges

Every edge type, including floating edges that attach to the nearest border.


Overview

Set an edge's type to choose its path: straight, step, smoothstep, simplebezier, button, data, animated, or floating. Floating edges connect to the nearest point on each node's border instead of a fixed handle.

Live demo

Drag the nodes, pan, and zoom — the canvas below is a real, running DashFlows component (no callbacks, just the rendered graph):

# File: docs/edges/demo.py

"""Live, callback-free demo for the docs page. Rendered via `.. exec::docs.edges.demo`."""
import dash_flows

nodes = [{'id': '0', 'type': 'default', 'data': {'label': 'straight'}, 'position': {'x': 60, 'y': 40}},
 {'id': '1', 'type': 'default', 'data': {'label': 'step'}, 'position': {'x': 320, 'y': 40}},
 {'id': '2', 'type': 'default', 'data': {'label': 'smoothstep'}, 'position': {'x': 60, 'y': 160}},
 {'id': '3',
  'type': 'default',
  'data': {'label': 'simplebezier'},
  'position': {'x': 320, 'y': 160}},
 {'id': '4', 'type': 'default', 'data': {'label': 'button'}, 'position': {'x': 60, 'y': 280}},
 {'id': '5', 'type': 'default', 'data': {'label': 'animated'}, 'position': {'x': 320, 'y': 280}}]

edges = [{'id': 's', 'source': '0', 'target': '1', 'type': 'straight'},
 {'id': 'st', 'source': '1', 'target': '2', 'type': 'step'},
 {'id': 'sm', 'source': '2', 'target': '3', 'type': 'smoothstep'},
 {'id': 'sb', 'source': '3', 'target': '4', 'type': 'simplebezier'},
 {'id': 'bt', 'source': '4', 'target': '5', 'type': 'button'},
 {'id': 'an', 'source': '5', 'target': '0', 'type': 'animated'}]

component = dash_flows.DashFlows(
    id="edges-demo",
    nodes=nodes,
    edges=edges,
    style={'border': '1px solid var(--mantine-color-default-border)',
 'borderRadius': '8px',
 'height': '440px'},
    showControls=True,
    fitView=True,
    colorMode='system',
)

:defaultExpanded: false :withExpandedButton: true

Examples

Each example below is a complete, runnable Dash app from the examples/ folder. Run any of them with python examples/<file>.

All Edge Types

A gallery of every edge type — default, straight, step, smoothstep, simplebezier, and button — laid out as a row of sources connecting to a row of targets, plus a callback that tracks edge deletions.

# File: examples/03_all_edge_types.py

"""
Example 03: All Edge Types
==========================
This example showcases all available edge types in DashFlows:
- default: Standard bezier curve edge (React Flow built-in)
- straight: Direct line between nodes
- step: Right-angled connections with sharp corners
- smoothstep: Right-angled with rounded corners
- simplebezier: Simple bezier curve
- button: Edge with interactive button (for deletion)
- animated: Edge with Dash component animation
"""

import dash
from dash import html, callback, Input, Output, State
import dash_flows

app = dash.Dash(__name__)

# Create a row of source nodes and a row of target nodes
nodes = [
    # Source nodes (top row)
    {"id": "s1", "type": "input", "data": {"label": "Default"}, "position": {"x": 50, "y": 50}},
    {"id": "s2", "type": "input", "data": {"label": "Straight"}, "position": {"x": 200, "y": 50}},
    {"id": "s3", "type": "input", "data": {"label": "Step"}, "position": {"x": 350, "y": 50}},
    {"id": "s4", "type": "input", "data": {"label": "SmoothStep"}, "position": {"x": 500, "y": 50}},
    {"id": "s5", "type": "input", "data": {"label": "SimpleBezier"}, "position": {"x": 650, "y": 50}},
    {"id": "s6", "type": "input", "data": {"label": "Button Edge"}, "position": {"x": 800, "y": 50}},

    # Target nodes (bottom row)
    {"id": "t1", "type": "output", "data": {"label": "Target 1"}, "position": {"x": 50, "y": 300}},
    {"id": "t2", "type": "output", "data": {"label": "Target 2"}, "position": {"x": 200, "y": 300}},
    {"id": "t3", "type": "output", "data": {"label": "Target 3"}, "position": {"x": 350, "y": 300}},
    {"id": "t4", "type": "output", "data": {"label": "Target 4"}, "position": {"x": 500, "y": 300}},
    {"id": "t5", "type": "output", "data": {"label": "Target 5"}, "position": {"x": 650, "y": 300}},
    {"id": "t6", "type": "output", "data": {"label": "Target 6"}, "position": {"x": 800, "y": 300}},
]

edges = [
    # Default edge (bezier curve) - React Flow's built-in
    {
        "id": "e1",
        "source": "s1",
        "target": "t1",
        "type": "default",
        "label": "Default",
        "animated": True,
    },

    # Straight edge - direct line
    {
        "id": "e2",
        "source": "s2",
        "target": "t2",
        "type": "straight",
        "label": "Straight",
    },

    # Step edge - sharp right angles
    {
        "id": "e3",
        "source": "s3",
        "target": "t3",
        "type": "step",
        "label": "Step",
    },

    # SmoothStep edge - rounded right angles
    {
        "id": "e4",
        "source": "s4",
        "target": "t4",
        "type": "smoothstep",
        "label": "SmoothStep",
        "data": {"borderRadius": 15},  # Custom corner radius
    },

    # SimpleBezier edge - simple curve
    {
        "id": "e5",
        "source": "s5",
        "target": "t5",
        "type": "simplebezier",
        "label": "SimpleBezier",
    },

    # Button edge - with delete button
    {
        "id": "e6",
        "source": "s6",
        "target": "t6",
        "type": "button",
        "data": {
            "label": "Click X to delete",
            "showButton": True,
            "buttonLabel": "x",
        },
    },
]

app.layout = html.Div([
    html.H1("All Edge Types Example"),
    html.P("Demonstrates every available edge type in DashFlows."),
    html.Ul([
        html.Li("Default: Standard bezier curve (animated in this example)"),
        html.Li("Straight: Direct line connection"),
        html.Li("Step: Right-angled path with sharp corners"),
        html.Li("SmoothStep: Right-angled with configurable rounded corners"),
        html.Li("SimpleBezier: Simple curved line"),
        html.Li("Button: Edge with interactive delete button"),
    ]),
    dash_flows.DashFlows(
        id="edge-types-flow",
        nodes=nodes,
        edges=edges,
        style={"height": "500px", "border": "1px solid #ddd"},
        fitView=True,
        showControls=True,
    ),
    html.Div(id="edge-deleted-info", style={"marginTop": "20px"}),
])

# Track edge deletions
@callback(
    Output("edge-deleted-info", "children"),
    Input("edge-types-flow", "edges"),
    prevent_initial_call=True,
)
def track_edge_changes(current_edges):
    if current_edges is None:
        return ""
    edge_count = len(current_edges)
    return f"Current edge count: {edge_count}"

if __name__ == "__main__":
    app.run(debug=True, port=8052)

:defaultExpanded: false :withExpandedButton: true

How it works

Floating Edges

Edges that dynamically attach to the closest border point of each node, instead of a fixed handle position — useful when nodes sit at irregular angles relative to each other.

# File: examples/26_floating_edges.py

"""
Example 26: Floating Edges
===========================
Demonstrates the 'floating' edge type which connects to the nearest point
on each node's border instead of fixed handle positions. This creates more
natural-looking connections, especially when nodes are positioned at angles.
"""

import dash
from dash import html, callback, Input, Output
import dash_flows

app = dash.Dash(__name__)

nodes = [
    {
        "id": "1",
        "type": "input",
        "data": {"label": "Data Source", "sublabel": "REST API"},
        "position": {"x": 0, "y": 0},
    },
    {
        "id": "2",
        "type": "default",
        "data": {"label": "Validate"},
        "position": {"x": 300, "y": -50},
    },
    {
        "id": "3",
        "type": "default",
        "data": {"label": "Transform"},
        "position": {"x": 150, "y": 200},
    },
    {
        "id": "4",
        "type": "default",
        "data": {"label": "Enrich"},
        "position": {"x": 450, "y": 150},
    },
    {
        "id": "5",
        "type": "output",
        "data": {"label": "Database", "sublabel": "PostgreSQL"},
        "position": {"x": 350, "y": 350},
    },
    {
        "id": "6",
        "type": "output",
        "data": {"label": "Dashboard", "sublabel": "Visualization"},
        "position": {"x": 50, "y": 400},
    },
]

# All edges use the 'floating' type - they connect to the nearest border point
edges = [
    {"id": "e1-2", "source": "1", "target": "2", "type": "floating", "label": "raw"},
    {"id": "e1-3", "source": "1", "target": "3", "type": "floating"},
    {"id": "e2-4", "source": "2", "target": "4", "type": "floating", "label": "valid"},
    {"id": "e3-4", "source": "3", "target": "4", "type": "floating"},
    {"id": "e3-6", "source": "3", "target": "6", "type": "floating"},
    {"id": "e4-5", "source": "4", "target": "5", "type": "floating", "label": "enriched"},
]

app.layout = html.Div([
    html.H1("Floating Edges"),
    html.P(
        "Floating edges connect to the nearest point on each node's border. "
        "Drag nodes around and watch the edges dynamically reattach to the closest point."
    ),
    dash_flows.DashFlows(
        id="floating-flow",
        nodes=nodes,
        edges=edges,
        style={"height": "600px", "border": "1px solid #ddd"},
        fitView=True,
        fitViewOptions={"padding": 0.2},
        showControls=True,
        showMiniMap=True,
        showBackground=True,
        colorScheme="ocean",
    ),
    html.Div(id="floating-info", style={"marginTop": "12px", "fontSize": "14px", "color": "#666"}),
])


@callback(
    Output("floating-info", "children"),
    Input("floating-flow", "clickedNode"),
)
def show_clicked(node):
    if not node:
        return "Click a node to see its info. Drag nodes to see floating edges update."
    return f"Clicked: {node['id']} - {node['data'].get('label', '')}"


if __name__ == "__main__":
    app.run(debug=True, port=8026)

:defaultExpanded: false :withExpandedButton: true

How it works


Source: /edges

Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs: