Skip to contents

Basic Usage

To create a basic flow using reactflow, you need to define nodes and edges and call the reactflow function with these arguments.

Note to label a node, you provide a label argument in the data list, whereas the label is a direct argument to an edge.

nodes <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1")),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"))
)

edges <- list(
  list(id = "e1-2", source = "1", target = "2", label = "Edge 1"),
  list(id = "e2-3", source = "2", target = "3"),
  list(id = "e1-3", source = "1", target = "3")
)
reactflow(
  nodes,
  edges
)

You can change the width of the output widget directly in the call to [reactflow()]:

reactflow(
  nodes,
  edges,
  width = "250px"
)

By default, you can use connect new edges by dragging from one node to another. To disable this, you can set

reactflow(
  nodes,
  edges,
  allow_edge_connection = FALSE
)

UI Elements

The reactflow package provides some easy to use UI elements to customize the usage and display of a flow. Namely [background()], [controls()], [mini_map()],

reactflow(
  nodes,
  edges,
  background = background(),
  controls = controls(),
  mini_map = mini_map()
)

Background

All arguments passed to background() are passed to the underlying react-flow component. The official background documentation can be found here: https://reactflow.dev/api-reference/components/background.


nodes <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1")),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"))
)

edges <- list(
  list(id = "e1-2", source = "1", target = "2", label = "Edge 1"),
  list(id = "e2-3", source = "2", target = "3"),
  list(id = "e1-3", source = "1", target = "3")
)

reactflow(
  nodes,
  edges,
  background = background()
)

An example using the extra arguments can be found below

reactflow(
  nodes,
  edges,
  background = background(
    color = "beige",
    variant = "lines",
    gap = 50,
    lineWidth = 2
  )
)

Multiple Backgrounds

You can also add multiple backgrounds to the flow by passing multiple background() elements.

reactflow(
  nodes,
  edges,
  background(
    id = 1,
    color = "beige",
    variant = "lines",
    gap = 40,
    lineWidth = 3
  ),
  background(
    id = 2,
    size = 4,
    offset = 3,
    color = "lightgray",
    variant = "dots"
  )
)

Controls

All arguments passed to controls() are passed to the underlying react-flow component. The official controls documentation can be found here: https://reactflow.dev/api-reference/components/controls.

nodes <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1")),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"))
)

edges <- list(
  list(id = "e1-2", source = "1", target = "2", label = "Edge 1"),
  list(id = "e2-3", source = "2", target = "3"),
  list(id = "e1-3", source = "1", target = "3")
)

reactflow(
  nodes,
  edges,
  controls = controls()
)

An example using the extra arguments can be found below

reactflow(
  nodes,
  edges,
  controls = controls(
    position = "top-right",
    orientation = "horizontal",
    showZoom = TRUE,
    showFitView = FALSE,
    showIntereactive = TRUE
  )
)

Mini Map

All arguments passed to mini_map() are passed to the underlying react-flow component. The official miniMap documentation can be found here: https://reactflow.dev/api-reference/components/minimap.

nodes <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1")),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"))
)

edges <- list(
  list(id = "e1-2", source = "1", target = "2", label = "Edge 1"),
  list(id = "e2-3", source = "2", target = "3"),
  list(id = "e1-3", source = "1", target = "3")
)

reactflow(
  nodes,
  edges,
  mini_map = mini_map(pannable = TRUE, zoomable = TRUE)
)

Styling

Each component can be styled individually or using CSS. Eg setting the following CSS class, will make all nodes green.

.react-flow__node {
  background-color: green !important;
}

See also app.R TODO

Nodes

Node Types

Note that nodes have different types, eg type = "input", "output", "default", and "group". See also official documentation at https://reactflow.dev/api-reference/types/node.

Node types of input do not have any ingoing connections, whereas outputs do not have any outgoing connections.

Direct Styling of Nodes

nodes2 <- list(
  list(id = "1", position = list(x = 0, y = 0),
       data = list(label = "I have direct Styling"),
       style = list("background-color" = "#2196f3",
                 color = "white",
                 "border-color" = "#0964AE",
                 "border-width" = "2px",
                 "font-size" = "1.25em",
                 filter = "drop-shadow(10px 10px 5px gray)")),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"))
)
reactflow(
  nodes = nodes2,
  edges = edges
)

Using className and custom CSS

Using classNames, we can assign custom CSS to the nodes in the mini-map.

.startNode {
  background-color: lightgreen;
}
.endNode {
  background-color: coral;
}
nodes2 <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1"),
       className = "startNode"),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"),
       className = "endNode")
)
reactflow(
  nodes = nodes2,
  edges = edges,
  mini_map = mini_map(),
  color_minimap = TRUE
)

Styling using htmlNodes

The reactflow R package brings its own html node Type, which allows you to style a node using HTML and CSS.

To use this, you have to set the type of the node to html and provide the HTML code in the html data argument.

nodes2 <- list(
  list(
    id = "1",
    type = "html", # this is required
    data = list(
      html = "I am a <b>HTML</b> node" # define your own HTML here
    ),
    position = list(x = 0, y = 0)
  ),
  list(
    id = "2",
    type = "html",
    data = list(
      html = as.character( # the HTML can be created using htmltools or shiny as well!
        htmltools::div(
          style = paste(
            "color: red; border: 2px solid gray; padding: 10px;",
            "border-radius: 10px; font-weight: 600;"
          ),
          
          "I am a ", htmltools::code("HTML"), "node"
        )
      )
    ),
    position = list(x = 200, y = 100)
  )
)

edges2 <- list(
  list(id = "e1-2", source = "1", target = "2", label = "Edge 1")
)

reactflow(
  nodes2,
  edges2
)

See also the Vignette on Fully Customized HTML Nodes.

LR Layouts

If you are using Left-to-Right (LR) layouts, either by specifying positions manually or using use_dagre = TRUE, dagre_direction = "LR", you can use a node with data.handle.position = "LR" to make the handle appear on the left side of a html node.

nodes2 <- list(
  list(
    id = "1",
    type = "html",
    data = list(
      html = "I am a <b>HTML</b> node",
      handle = list(direction = "LR") # this is new here!
    ),
    position = list(x = 0, y = 0)
  ),
  list(
    id = "2",
    type = "html",
    data = list(
      html = as.character( # the HTML can be created using htmltools or shiny as well!
        htmltools::div(
          style = paste(
            "color: red; border: 2px solid gray; padding: 10px;",
            "border-radius: 10px; font-weight: 600;"
          ),
          
          "I am a ", htmltools::code("HTML"), "node"
        )
      ),
      handle = list(direction = "LR") # this is new here!
    ),
    position = list(x = 200, y = 0)
  )
)

edges2 <- list(
  list(id = "e1-2", source = "1", target = "2", label = "Edge 1")
)

reactflow(
  nodes2,
  edges2
)

Edges

Edge Types and Styling

ReactFlow knows different edge types, these are

  • straight
  • step
  • smoothstep
  • simplebezier

Additionally, each edge can be animated by setting animated = TRUE.

The full documentation can be found here: https://reactflow.dev/api-reference/types/edge

nodes2 <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1")),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 200, y = 200), data = list(label = "Node 3"))
)

edges2 <- list(
  list(id = "e1-2", source = "1", target = "2", label = "straight",
       type = "straight"),
  list(id = "e2-3", source = "2", target = "3", label = "smoothstep + animated", 
       type = "smoothstep", animated = TRUE),
  list(id = "e1-3", source = "1", target = "3", label = "simplebezier",
       type = "simplebezier")
)

reactflow(
  nodes2,
  edges2
)

Note that you can slow down the animation by using the following CSS

.react-flow__edge.animated path {
  animation: dashdraw 2s linear infinite;
}
edges2 <- list(
  list(id = "e1-2", source = "1", target = "2", label = "straight",
       type = "straight", animated = TRUE),
  list(id = "e2-3", source = "2", target = "3", label = "smoothstep + animated", 
       type = "smoothstep", animated = TRUE),
  list(id = "e1-3", source = "1", target = "3", label = "simplebezier",
       type = "simplebezier", animated = TRUE)
)

reactflow(
  nodes,
  edges2
)

Direct Styling

Using className and custom CSS

Mini Map

The official miniMap documentation can be found here: https://reactflow.dev/api-reference/components/minimap. For example, the nodeColor argument can be used to change the color of the nodes in the mini map.

reactflow(
  nodes,
  edges,
  mini_map = mini_map(
    pannable = TRUE,
    zoomable = TRUE,
    nodeColor = "coral",
    position = "top-right",
    maskColor = "lightgray"
  )
)

Using classNames, we can assign custom CSS to the nodes in the mini-map.

.startNode {
  background-color: lightgreen;
}
.endNode {
  background-color: coral;
}
nodes2 <- list(
  list(id = "1", position = list(x = 0, y = 0), data = list(label = "Node 1"),
       type = "input"),
  list(id = "2", position = list(x = 100, y = 100), data = list(label = "Node 2")),
  list(id = "3", position = list(x = 0, y = 200), data = list(label = "Node 3"),
       type = "output")
)
reactflow(
  nodes = nodes2,
  edges = edges,
  mini_map = mini_map(
    nodeColor = JS("
    function nodeColor(node) {
      switch (node.type) {
        case 'input':
          return 'coral';
        case 'output':
          return 'lightblue';
        default:
          return 'gray';
      }
    }")
  )
)

Background

Controls

There is very little styling that can be applied to [controls()] directly. However, we can apply styling using the CSS class react-flow__controls.

Layouting

Normally, the layout of the nodes is done automatically by specifying the position arguments of the nodes. There are however some layouting algorithms that can be used to automatically layout the nodes. One solution is to use a tool like ggraph and its create_layout() function (with some transformation done to x and y).

Alternatively, you can use the built-in dagre solution.

Automatic Layout using dagre

nodes_orig <- list(
  list(id = "start", type = "input", data = list(label = "Start Node")),
  list(id = "mid", data = list(label = "Mid Node")),
  list(id = "mid2", data = list(label = "Mid Node 2")),
  list(id = "end", type = "output", data = list(label = "End Node"))
)
edges_orig <- list(
  list(source = "start", target = "mid", id = "start-mid"),
  list(source = "start", target = "mid2", id = "start-mid2"),
  list(source = "mid", target = "end", id = "mid-end"),
  list(source = "mid2", target = "end", id = "mid2-end")
)
reactflow(
  nodes = nodes_orig,
  edges = edges_orig,
  
  use_dagre = TRUE, dagre_direction = "TB",
  dagre_config = list(nodeWidth = 250, nodeHeight = 50)
)

Interactivity with Shiny

library(shiny)
library(bslib)
library(reactflow)

ui <- page_sidebar(
  sidebar = sidebar(
    h4("Add Node"),
    textInput("node_name", "Node Name"),
    selectInput("node_prev", "Previous Node", ""),
    selectInput("node_next", "Next Node", ""),
    actionButton("add_node", "Add Node"),
    hr(),
    h4("Selected Element"),
    verbatimTextOutput("selected_el")
  ),
  card(
    reactflowOutput("my_graph", height = "100%"),
  )
)

nodes_orig <- list(
  list(id = "start", data = list(label = "Start Node")),
  list(id = "mid", data = list(label = "Mid Node")),
  list(id = "end", data = list(label = "End Node"))
)

edges_orig <- list(
  list(source = "start", target = "mid", id = "start-mid"),
  list(source = "mid", target = "end", id = "mid-end")
)

server <- function(input, output, session) {
  output$selected_el <- renderPrint(str(input$my_graph_click))

  nodes <- reactiveVal(nodes_orig)
  edges <- reactiveVal(edges_orig)
  
  observeEvent(nodes(), {
    all_nodes <- sapply(nodes(), "[[", "id")
    updateTextInput(session, "node_name", value = "")
    updateSelectInput(session, "node_prev", choices = c("", all_nodes))
    updateSelectInput(session, "node_next", choices = c("", all_nodes))
  })
  
  
  observeEvent(input$add_node, {
    new_id <- as.character(length(nodes()) + 1)
    
    new_node <- list(id = new_id, data = list(label = input$node_name))
    
    from <- input$node_prev
    to <- input$node_next
    
    new_edge <- list(
      if (from != "") list(id = paste(from, new_id, sep = "-"), source = from, target = new_id),
      if (to != "") list(id = paste(new_id, to, sep = "-"), source = new_id, target = to)
    )
    new_edge <- new_edge[sapply(new_edge, length) > 0]
    
    nodes(c(nodes(), list(new_node)))
    edges(c(edges(), new_edge))
  })
  
  output$my_graph <- renderReactflow({
    reactflow(
      nodes = nodes(),
      edges = edges(),
      
      controls(),
      clickId = "my_graph_click",
      
      use_dagre = TRUE, dagre_direction = "TB",
      dagre_config = list(nodeWidth = 250, nodeHeight = 50),
      fitView = TRUE,
      allow_edge_connection = FALSE, # disable edge creation
      nodesDraggable = TRUE # default value, can be set to FALSE to disable dragging
    )
  })
}

shinyApp(ui, server)

Styling Selected Elements

Using CSS, we can style the selected elements in the flow. Note that it’s easier to override the CSS variable for coloring the edges. See also a list of all ReactFlow CSS variables here: https://reactflow.dev/learn/customization/theming

.react-flow__node.selected {
  background-color: coral !important;
  color: white !important;
}
:root {
  --xy-edge-stroke-selected: coral;
}
library(shiny)
library(bslib)
library(reactflow)

ui <- page_sidebar(
  tags$head(tags$style(
    ".react-flow__node.selected {
       background-color: coral !important;
       color: white !important;
     }
     :root {
        --xy-edge-stroke-selected: coral;
      }"
  )),
  card(
    reactflowOutput("my_graph")
  )
)

server <- function(input, output, session) {
  output$my_graph <- renderReactflow({
    reactflow(
      nodes = list(
          list(id = "start", type = "input", data = list(label = "Start Node"),
               position = list(x = 0, y = 0)),
          list(id = "mid", data = list(label = "Mid Node"),
               position = list(x = 0, y = 100)),
          list(id = "end", type = "output", data = list(label = "End Node"),
               position = list(x = 0, y = 200))
        )
      ,
      edges = list(
        list(source = "start", target = "mid", id = "start-mid"),
        list(source = "mid", target = "end", id = "mid-end")
      )
      
    )
  })
}

shinyApp(ui, server)