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.
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 output
s 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 className
s, we can assign custom CSS to the nodes
in the mini-map.
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
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
)
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 className
s, we can assign custom CSS to the nodes
in the mini-map.
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';
}
}")
)
)
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)