> For AI agents: the complete documentation index is at [llms.txt](https://reflex.dev/docs/llms.txt). Markdown versions are available by appending `.md` or sending `Accept: text/markdown`.

# Adding Interactivity to Your Flow

This guide shows how to create an interactive flow in Reflex, allowing you to select, drag, and connect nodes and edges.

## Define the State

We start by defining the nodes and edges of the flow. The `FlowState` class holds the nodes and edges as state variables and includes event handlers to respond to changes.

```python
import reflex as rx
import reflex_enterprise as rxe
from reflex_enterprise.components.flow.types import Node, Edge


class FlowState(rx.State):
    nodes: list[Node] = [
        {
            "id": "1",
            "type": "input",
            "position": {"x": 100, "y": 100},
            "data": {"label": "Node 1"},
        },
        {
            "id": "2",
            "type": "default",
            "position": {"x": 300, "y": 200},
            "data": {"label": "Node 2"},
        },
    ]

    edges: list[Edge] = [
        {
            "id": "e1-2",
            "source": "1",
            "target": "2",
            "label": "Connection",
            "type": "step",
        }
    ]
```

## Add Event Handlers

Event handlers allow the flow to respond to user interactions such as dragging nodes, updating edges, or creating new connections.

```python
@rx.event
def set_nodes(self, nodes: list[Node]):
    self.nodes = nodes


@rx.event
def set_edges(self, edges: list[Edge]):
    self.edges = edges
```

- set_nodes updates nodes when they are moved or edited.

- set_edges updates edges when they are modified or deleted.

Note that these are plain setters — they receive the already-updated list. The change-application logic lives in the component wiring, shown next.

## Render the Interactive Flow

Finally, we render the flow using **rxe.flow**, passing in the state and event handlers. Additional UI features include zoom/pan controls, a background grid, and a mini-map for navigation.

```python
def interactive_flow():
    return rx.box(
        rxe.flow(
            rxe.flow.controls(),
            rxe.flow.background(),
            rxe.flow.mini_map(),
            nodes=FlowState.nodes,
            edges=FlowState.edges,
            on_nodes_change=lambda node_changes: FlowState.set_nodes(
                rxe.flow.util.apply_node_changes(FlowState.nodes, node_changes)
            ),
            on_edges_change=lambda edge_changes: FlowState.set_edges(
                rxe.flow.util.apply_edge_changes(FlowState.edges, edge_changes)
            ),
            on_connect=lambda connection: FlowState.set_edges(
                rxe.flow.util.add_edge(connection, FlowState.edges)
            ),
            fit_view=True,
            attribution_position="bottom-right",
        ),
        height="100vh",
        width="100vw",
    )
```

- `on_nodes_change` fires when nodes are dragged, selected, resized, or removed.
- `on_edges_change` fires when edges are selected or removed.
- `on_connect` fires when the user drags a connection between two handles; `rxe.flow.util.add_edge` builds the new edge list from the connection.

Make sure to set the `height` and `width` of the container around the flow — the flow fills its parent, so without explicit dimensions it will not be visible.

## Controlled vs. Uncontrolled Flows

Passing `nodes` and `edges` makes the flow **controlled**: your state is the source of truth, and the canvas renders exactly what the state contains. A controlled flow must wire `on_nodes_change` and `on_edges_change` as shown above, otherwise user interactions (dragging, selecting, deleting) are discarded.

Passing only `default_nodes` and `default_edges` makes the flow **uncontrolled**: the component manages changes internally, but your state never learns about them.

## Where Changes Get Applied

`rxe.flow.util.apply_node_changes` and `rxe.flow.util.apply_edge_changes` must be used inside of component code — in the lambda wired to `on_nodes_change` / `on_edges_change` — and never inside of state code. They evaluate on the client and produce the updated list, which is then passed to a plain setter event handler:

```python
rxe.flow(
    ...,
    on_nodes_change=lambda changes: FlowState.set_nodes(
        rxe.flow.util.apply_node_changes(FlowState.nodes, changes)
    ),
)
```

Do not call these utilities from within an `@rx.event` handler; the state side should only receive and store the resulting list.
