Timeline
What's new?
We're always working on the React Flow docs and the library.
This is a timeline of the things we've added or changed so far.

React Flow 12.9.0
This update is huge! We added a new EdgeToolbar component, it’s now possible to start a
selection above a node and child nodes of different parents won’t overlap anymore:
Minor Changes
- #5544  Add 
EdgeToolbarcomponent - #5550 Prevent child nodes of different parents from overlapping
 - #5551 Allow to start a selection above a node
 
Patch Changes

React Flow 12.8.5
Patch Changes
- #5480 Prevent multi-touch events while making a new connection
 - #5482 Make isNodeIntersecting behave the same as getIntersectingNodes
 - #5509 Prevent calling onResizeEnd if node was not resized
 - #5511 Fix regression: elevate edges if connected nodes are selected
 - #5497 Skip eagerly rendering nodes when node dimensions and handles are predefined
 - #5455 Thanks @Sec-ant ! - Fix warning when display is set to none on the wrapper div
 


React Flow 12.8.3
A new version of React Flow is out. With 12.8.3 you get a lot of bug fixes and a great improvement for handles. It’s now possible to position child content of a handle outside of the handle itself and still use it as a starting point for connections as you can see in this example:
Patch Changes
- #5428 Be able to use detached handle content as a starting point for a connection
 - #5419  Make edge markers fallback to
--xy-edge-strokeCSS variable when marker color is null - #5453 Snap selection instead of separate nodes when snap grid is enabled
 - #5444  Export 
MiniMapNodeto use it for custom mini map nodes - #5415 Allow strings and enums for marker types
 - #5436 Prevent a 0 added to the markup for edges when interactionWidth is 0
 - #5443 Use 1 as the default for interactive Minimap zoom step
 - #5448  Use correct 
HandleConnectiontype for HandleonConnect - #5420  Omit 
defaultValuefromNode’sdomAttributesto fix type incompatibility when usingWritableDraft 


Rebrush React Flow UI
We have made some significant improvements to React Flow UI (formerly known as React Flow components). These changes enhance the functionality, visual look and usability of the components, to improive the general developer experience.
Re-organize components
Some components have been moved to examples, while others have been consolidated in a new structure:
- Nodes Utilities: These components can be used as building blocks for creating custom nodes.
 - Custom Nodes: These are fully functional nodes that can be used directly in your application.
 - Handles: These components are used to create connection points inside nodes.
 - Custom Edges: Fully functional edges that can be used out of the box.
 - Controls: Collection of interactive controls.
 - Miscellaneous: Various utility components that don’t fit into the other categories,
like 
DevTools. 
Find all of them in the React Flow UI page.
BaseNode enhancements
Our BaseNode component has been fully revamped, to provide a more consistent experience with shadcn UI , and the rest of our React Flow UI component library.
The new BaseNode component now includes improved styling and wrapper components,
aligning to shadcn UI design principles.
Just like a shadcn UI Card component , the
BaseNode component now exports
BaseNodeHeaderandBaseNodeHeaderTitlefor the header section,BaseNodeContentfor the main content area andBaseNodeFooterfor the footer section.
This structure allows for better organization of content within the node, making it easier to create complex node layouts.
Improved examples and nodes
We have also added a few new components and improved existing ones. Our component pages now include more comprehensive examples that showcase the new features and capabilities of the components. For example:
- New 
NodeAppendixcomponent, which can be used to add additional information or controls to nodes, like aNode Badge! - The 
AnnotationNodecomponent has been moved to an example usage ofBaseNode, to demonstrate how to style theBaseNode. - The 
StatusIndicatornow includes a variant with an overlaying spinner, and improved usage examples. - The 
TooltipNodecomponent, has been improved and moved toNodeTooltip. It is no longer a custom node, but rather an utility component that you can use to wrap a custom node with a tooltip. 
No more selected prop
You don’t need to pass the selected prop to the BaseNode or its related components
anymore. Styling the selected state is now handled automatically by tailwind CSS
selectors.
However, selected is still a valid prop for nodes in React Flow, and you can still use
it to determine if a node is selected or not in your custom components. If you do not need
the selected prop for custom logic, but you only use it for styling, you can safely
remove it from your components, and you can follow how BaseNode is implemented to
achieve custom styling for your custom selected nodes.
export const BaseNode = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
  ({ className, ...props }, ref) => (
    <div
      ref={ref}
      className={cn(
        'relative rounded-md border bg-card text-card-foreground',
        'hover:ring-1',
        // React Flow displays node elements inside of a `NodeWrapper` component,
        // which compiles down to a div with the class `react-flow__node`.
        // When a node is selected, the class `selected` is added to the
        // `react-flow__node` element. This allows us to style the node when it
        // is selected, using Tailwind's `&` selector.
        '[.react-flow\\_\\_node.selected_&]:border-muted-foreground',
        '[.react-flow\\_\\_node.selected_&]:shadow-lg',
        className,
      )}
      tabIndex={0}
      {...props}
    />
  ),
);
BaseNode.displayName = 'BaseNode';Feedback
We hope these improvements make your experience with React Flow UI even better. If you have any feedback or suggestions, please let us know via mail or Discord !

Learn section rework
Restructured and updated content
We went over and updated our learn section. Here’s what’s changed:
- We slimmed down most pages and deleted some fluff that we felt didn’t contribute to a better understanding of the library.
 - Quickstart is now the landing page to rule them all, with installation and example setup.
 - Getting started and concepts have been merged into one section.
 - The customization and concepts section have been updated. Our mental approach was to shorten and clearly separate pages by context, making them easy to digest when read both standalone and in succession.
 - In general texts include more interlinking between our docs sections, snippets now include highlights and the layout and headings have been improved for easier scanning of the text.
 
Reworked code preview
Our code preview component has been updated with a sleek new design with an action bar that allows you to toggle, copy, refresh or open the code in a sandbox. The default size has also been adjusted in some places to integrate into the text better. Here’s what it looks like:

Feedback
We hope these changes make your introduction to React Flow even better. If you have feedback or suggestions, please let us know via mail or Discord !


React Flow 12.7.1
Patch Changes
- #5354 Add TSDoc annotations
 - #5333 Add missing type exports
 - #5353  Thanks @aidanbarrett ! - Add missing 
FinalConnectionStateparameter toonReconnectEndprop types 

React Flow 12.7.0
This release comes with some improvements for a better accessibility and much more:
Minor Changes
- #5299  Add 
ariaRoleprop to nodes and edges - #5277  Add 
ariaLabelConfigprop for customizing UI text like aria labels and descriptions. - #5317  Add 
domAttributesoption for nodes and edges - #5308  Focus nodes on tab if not within the viewport and add a new prop 
autoPanOnNodeFocus - #5326 Prevent NodeResizer controls to become too small when zooming out
 - #5276  Add an 
easeandinterpolateoption to all function that alter the viewport - #5280 Improve typing for Nodes
 



React Flow 12.5.6
Patch Changes

React Flow 12.5.5
Patch Changes
- #5172  Thanks @dimaMachina ! - Improve TSDoc comments for 
useNodesData,useReactFlow,isNodeandisEdge - #5165  Thanks @dimaMachina ! - Improve TSDoc comments for 
useViewport,useUpdateNodeInternals,useOnSelectionChange,useNodesInitializedhooks andUseOnSelectionChangeOptions,UseNodesInitializedOptionstypes - #5171  Thanks @dimaMachina ! - Improve TSDoc comments for 
ReactFlowProps - #5154  Thanks @ibagov ! - Improve TSDoc comments for 
onNodesChange - #5174  Thanks @dimaMachina ! - Improve TSDoc comments for 
BaseEdgeProps - #5159  Thanks @dimaMachina ! - Improve TSDoc comments for 
useConnectionhook - #5167  Thanks @dimaMachina ! - Improve TSDoc comments for 
useEdges,useInternalNode,useNodesanduseNodeIdhooks - #5163  Thanks @dimaMachina ! - Improve TSDoc comments for 
useNodesStateanduseEdgesStatehook - #5160  Thanks @dimaMachina ! - Improve TSDoc comments for 
type UseHandleConnectionsParamsanduseHandleConnectionshook - #5162  Thanks @dimaMachina ! - Improve TSDoc comments for 
type UseNodeConnectionsParamsanduseNodeConnectionshook - #5164  Thanks @dimaMachina ! - Improve TSDoc comments for 
type UseOnViewportChangeOptionsanduseOnViewportChangehook - #5166  Thanks @dimaMachina ! - Improve TSDoc comments for 
useStorehook - #5170  Thanks @dimaMachina ! - Improve TSDoc comments for 
interface GetSimpleBezierPathParamsandgetSimpleBezierPath - #5161  Thanks @dimaMachina ! - Improve TSDoc comments for 
type UseKeyPressOptionsanduseKeyPresshook 

React Flow 12.5.0
fitView just got a lot better!
Have ever struggled with making fitView work right after adding or changing your nodes? Does your code look something like this?
setNodes((nodes) => [nodes, ...newNode]);
requestAnimationFrame(() => {
  fitView();
});
// renders the node first and then fits the view :(Well, you are in for a treat! No more hacks, no more setTimeout or requestAnimationFrame and no more split second frames of unfitted views!
setNodes((nodes) => [nodes, ...newNode]);
fitView(); // it just works.
// adding a new node and fitting the view happens at the same timeOne more thing
You might have realized that the padding value for fitViewOptions is quite a weird fella! What does padding: 0.3 even mean? Well we don’t know either, so you you can now pass pixel values '25px', viewport percentages '10%' and true pros can now even
const fitViewOptions = {
  padding: {
    /** horizontal */
    x: '100px',
    /** vertical */
    y: '50px',
    /** e.g. top overwrites x */
    top: '25px',
    /** mix and match units */
    left: '15%',
    /** legacy units still work */
    bottom: 0.1,
    /** have a modal on the right that stretches 50% over the screen? */
    right: '50%',
  },
};setNodes((nodes) => [nodes, ...newNode]);
fitView(); // it just works.
// adding a new node and fitting the view happens at the same timeNew Features
- #5067 Define different fitView paddings for each side in ‘px’ or ’%’.
 
Patch Changes
- #5067 Fix fitView not working immediately after adding new nodes
 - #5059 Prevent onPaneClick when connection is in progress.
 - #5093 Hidden nodes are not displayed in the mini map anymore
 - #5090 Release key even when an inout field is focused
 - Thanks @dimaMachina ! - for improving TSDoc comments for 
BackgroundProps,EdgeLabelOptions,ControlProps,NodeToolbarProps,EdgeLabelRendererProps,EdgeLabelOptionsandEdgeTextProps 

React Flow 12.4.3
Patch Changes
- #5010 Add more TSDocs to components, hooks, utils funcs and types
 - #4991 Thanks @waynetee ! - Fix viewport shifting on node focus
 - #5013  Pass 
NodeTypetype argument fromReactFlowPropstoconnectionLineComponentproperty. - #5008 Add package.json to exports
 - #5012 Add snapGrid option to screenToFlowPosition and set snapToGrid to false
 - #5003 Thanks @dimaMachina ! - repair lint command
 - #4991 Thanks @waynetee ! - Prevent viewport shift after using Tab
 



React Flow 12.4.0
New year, new minor release :) This release contains mostly fixes but also introduces a new useNodeConnections that is the successor of useHandleConnections.
Minor Changes
- #4725  Add 
useNodeConnectionshook to track all connections to a node. Can be filtered by handleType and handleId. 
Patch Changes

React Flow 12.3.6
Patch Changes
- #4846 Make it possible to use expandParent with immer and other immutable helpers
 - #4865 Add group node to BuiltInNode type. Thanks @sjdemartini !
 - #4877 Fix intersections for nodes with origins other than [0,0]. Thanks @gmvrpw !
 - #4844 Allow custom data-testid for ReactFlow component
 - #4816 Type isValidConnection prop correctly by passing EdgeType
 - #4855  Thanks @mhuggins ! - Support passing 
pathelement attributes toBaseEdgecomponent. - #4862 Prevent default scrolling behavior when nodes or a selection is moved with an arrow key press.
 - #4875 Prevent unnecessary rerenders of edges when resizing the flow.
 - #4826 Forward ref of the div inside Panel components.
 

Our examples have a fresh new look
We’ve revamped the styles across all our React Flow examples. Plus, we added a new theme file to show you how to customize the style and interactions of your flows.
We think it looks fantastic and can’t wait to hear your feedback. Check out our updated Feature Overview below, along with all of our other updated examples.
import React, { useCallback } from 'react';
import {
  ReactFlow,
  addEdge,
  MiniMap,
  Controls,
  Background,
  useNodesState,
  useEdgesState,
} from '@xyflow/react';
 
import '@xyflow/react/dist/style.css';
 
import {
  nodes as initialNodes,
  edges as initialEdges,
} from './initial-elements';
 
import AnnotationNode from './AnnotationNode';
import ToolbarNode from './ToolbarNode';
import ResizerNode from './ResizerNode';
import CircleNode from './CircleNode';
import TextInputNode from './TextInputNode';
import ButtonEdge from './ButtonEdge';
 
const nodeTypes = {
  annotation: AnnotationNode,
  tools: ToolbarNode,
  resizer: ResizerNode,
  circle: CircleNode,
  textinput: TextInputNode,
};
 
const edgeTypes = {
  button: ButtonEdge,
};
 
const nodeClassName = (node) => node.type;
 
const OverviewFlow = () => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  const onConnect = useCallback(
    (params) => setEdges((eds) => addEdge(params, eds)),
    [],
  );
 
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
      fitView
      attributionPosition="top-right"
      nodeTypes={nodeTypes}
      edgeTypes={edgeTypes}
    >
      <MiniMap zoomable pannable nodeClassName={nodeClassName} />
      <Controls />
      <Background />
    </ReactFlow>
  );
};
 
export default OverviewFlow;
React Flow 12.3.5
Patch Changes
- #4789 Support key combinations which include + (e.g., Control++ resolves to the combination Control and +).
 - #4796 Thanks @Aki-7 ! - Fix number of issues connected to batching node & edge updates.
 - #4790 Fix node dragging & resizing while zooming on flow that does not cover whole browser window.
 - #4782 Fix node intersections in nested flow.
 

Introducing React Flow Components - powered by shadcn CLI
We’ve been interested in developing reusable components for React Flow for a while now. With the recent releases of shadcn CLI, we’ve made that happen! Some interesting components from the initial set include:
- 
A database schema node that makes it easy to visualize tables and relationships between columns.
 - 
A zoom slider for more convenient control over the viewport zoom level.
 - 
Debugging components that make it easier to inspect a node’s properties and the state of your flow.
 
We’re excited to see what you build with these components, and we’re looking forward to hearing your feedback! Please open issues on our web repo if you run into any problems or have any suggestions for new components, and definitely tweet at us at @xyflowdev if you build something cool with them!
If you want to read the entire release blog post, you can find it on the xyflow blog here .




We've updated our example viewer!
For a long time now our examples have been built on top of Sandpack . This has been a powerful tool for us to provide interactive examples in our docs but it’s also come at a cost.
The problems
We liked Sandpack, but we kept brushing up against some pain points that ultimately we decided we couldn’t ignore.
- 
Our examples were slow to load. Sandpack is an impressive tool, but it is also a heavy one. The Sandpack client itself takes a moment to load, and then if an example included dependencies those would need to be fetched as well. For one-off example pages this wasn’t terrible, but particularly for longer docs pages like our guides or tutorials this could really kill the momentum.
 - 
Sandpack didn’t properly support Svelte when we first released Svelte Flow. Ultimately we ended up developing a separate SvelteKit app to host our Svelte examples and adapted our example viewer to switch between Sandpack examples and simple iframe embeds.
 - 
Finally, developing new examples was a pain. The source code for our React examples lived in folders deep inside our example viewer component and had special handling of certain files or formats that made authoring examples quite difficult: each change to an example would trigger a hot reload of our docs, which meant waiting for Sandpack to reload and re-render the example again and again.
 
And on top of all that we had an entirely separate app we used to generate the screenshots for our examples overview page!
The solution
We were quite happy with how our Svelte examples worked (thank you Peter), and decided we wanted to explore a unified solution that would work for both our Svelte and React examples. In the end, we landed up with something even simpler than our SvelteKit app, dropping the need for a server entirely and instead serving everything from a static site.
We’ve created a single example-apps app in our monorepo that uses vite to serve our examples during development and build them into static files for production. If you’re curious, you can find a plain directory of all our examples over at examples-apps.xyflow.com.
We also made authoring examples easier. Developing examples now more closely resembles developing a standalone app, and we put together a simple scaffold script to help us quickly create new examples:
The scaffold script helps you quickly put together a new example for either
reactflow.dev or svelteflow.dev by copying over the boilerplate. All arguments
are _required_.
 
USAGE:
 
pnpm scaffold <FRAMEWORK> <ROUTE>
 
EXAMPLES:
 
pnpm scaffold react blog/web-audio/demo
 
pnpm scaffold svelte guides/getting-started
 
ARGUMENTS:
 
FRAMEWORK 'react' | 'svelte'
 
              The framework the example will be written in. This affects where
              the generated files are placed in conjunction with the ROUTE
              argument.
 
ROUTE string
 
              The route fragment the example app will be served at when combined
              with the FRAMEWORK argument. For example, calling the script as
              `pnpm scaffold react examples/nodes/custom-node` will scaffold
              the example and make it accessible at
              '/react/examples/nodes/custom-node/index.html'.Are there any downsides?
We’ve lost one big feature in the transition: the ability to edit examples directly on the docs site. For some users this might be a big deal, but to compensate we now support opening the examples in StackBlitz in addition to CodeSandbox!
Wrap up
That’s all for now folks . For most people this change should be seamless with a free boost to performance to boot. If we’ve managed to break anything in the migration please let us know by opening an issue , and if you think the changes are excited we’d love if you tweeted about it and tagged us @xyflowdev !


React Flow 12.3.1
Patch Changes
- 
#4670 Fix initial
fitViewnot working correctly fornodeOriginother than [0,0] - 
#4670 Improve
fitViewto respect clamped node positions based onnodeExtent - 
#4653 Calculate viewport dimensions in
fitViewinstead of using stored dimensions. Fixes #4652 - 
#4681 Fix crash when deleting nodes while dragging. Closes #4677
 

React Flow 12.3.0
Minor Changes
- #4477  
d5592e75AddgetNodesBoundstouseReactFlow/useSvelteFlowhook as the new recommended way of determining node bounds. 
Patch Changes

New edge examples
Here’s a care drop of new edge examples including how to animate nodes along an edge path, how to create temporary edges, and a demo of every connection event. We hope this new bundle of examples will help you level up your flow game!
import React, { useEffect, useMemo } from 'react';
import {
  BaseEdge,
  getBezierPath,
  useReactFlow,
  type Edge,
  type EdgeProps,
} from '@xyflow/react';
 
export type AnimatedNodeEdge = Edge<{ node: string }, 'animatedNode'>;
 
export function AnimatedNodeEdge({
  id,
  data = { node: '' },
  sourceX,
  sourceY,
  targetX,
  targetY,
  sourcePosition,
  targetPosition,
}: EdgeProps<AnimatedNodeEdge>) {
  const { getNode, updateNode } = useReactFlow();
  const [edgePath] = getBezierPath({
    sourceX,
    sourceY,
    sourcePosition,
    targetX,
    targetY,
    targetPosition,
  });
  const selector = useMemo(
    () => `.react-flow__node[data-id="${data.node}"]`,
    [data.node],
  );
 
  useEffect(() => {
    const node = document.querySelector(selector) as HTMLElement;
 
    if (!node) return;
 
    node.style.offsetPath = `path('${edgePath}')`;
    node.style.offsetRotate = '0deg';
    // This property is fairly new and not all versions of TypeScript have it
    // in the lib.dom.d.ts file. If you get an error here, you can either
    // ignore it or add the property to the CSSStyleDeclaration interface
    // yourself.
    //
    // @ts-expect-error
    node.style.offsetAnchor = 'center';
 
    let wasDraggable = getNode(data.node).draggable;
 
    updateNode(data.node, { draggable: false });
 
    return () => {
      node.style.offsetPath = 'none';
      updateNode(data.node, { draggable: wasDraggable });
    };
  }, [selector, edgePath]);
 
  useEffect(() => {
    const node = document.querySelector(selector) as HTMLElement;
 
    if (!node) return;
 
    const keyframes = [{ offsetDistance: '0%' }, { offsetDistance: '100%' }];
    const animation = node.animate(keyframes, {
      duration: 2000,
      direction: 'alternate',
      iterations: Infinity,
    });
 
    return () => {
      animation.cancel();
    };
  }, [selector]);
 
  return <BaseEdge id={id} path={edgePath} />;
}This is a breakdown of what’s been added:
- 
Two examples in one showing how to animate SVG elements and other nodes along an edge path.
 - 
A new example showing how to create a temporary edge attached to only one handle. These edges can be picked back up and connected at a later time.
 - 
We have a lot of events related to connections so we’ve created a small demo showing every connection and event and when they are triggered.
 

New tutorial – Create a slide show presentation with React Flow
We recently published the findings from our React Flow 2023 end-of-year survey with an interactive presentation of the key findings, using React Flow itself. There were lots of useful bits built into this slideshow app, so we wanted to share how we built it!

New Release 12.0.0
React Flow 12 is finally out! With a new package name @xyflow/react!
Main features
- SSR / SSG: you can define 
width,heightandhandlesfor the nodes. This makes it possible to render a flow on the server and hydrate on the client: SSR guide- Details: In v11, 
widthandheightwere set by the library as soon as the nodes got measured. This still happens, but we are now usingmeasured.widthandmeasured.heightto store this information. In the previous versions there was always a lot of confusion aboutwidthandheight. It’s hard to understand, that you can’t use it for passing an actual width or height. It’s also not obvious that those attributes get added by the library. We think that the new implementation solves both of the problems:widthandheightare optional attributes that can be used to define dimensions and the measured dimensions are stored inmeasured. 
 - Details: In v11, 
 - Reactive Flows: The new hooks 
useHandleConnectionsanduseNodesDataand the newupdateNodeandupdateNodeDatafunctions can be used for managing the data flow between your nodes: computing flows guide- Details: Working with reactive flows is super common. You update node A and want to react on those changes in the connected node B. Until now everyone had to come up with a custom solution. With this version we want to change this and give you performant helpers to handle this. If you are excited about this, you can check out this example:
 
 - Dark mode and css variables: React Flow now comes with a built-in dark mode, that can be toggled by using the new 
colorModeprop (”light”, “dark” or “system”): dark mode example- Details: With this version we want to make it easier to switch between dark and light modes and give you a better starting point for dark flows. If you pass colorMode=”dark”, we add the class name “dark” to the wrapper and use it to adjust the styling. To make the implementation for this new feature easier on our ends, we switched to CSS variables for most of the styles. These variables can also be used in user land to customize a flow.
 
 
More features and updates
There is more! Besides the new main features, we added some minor things that were on our list for a long time. We also started to use TS docs for better docs. We already started to add some docs for some types and hooks which should improve the developer experience.
useConnectionhook: With this hook you can access the ongoing connection. For example, you can use it for colorizing handles styling a custom connection line based on the current start / end handles.- Controlled 
viewport: This is an advanced feature. Possible use cases are to animate the viewport or round the transform for lower res screens for example. This features brings two new props:viewportandonViewportChange. ViewportPortalcomponent: This makes it possible to render elements in the viewport without the need to implement a custom node.onDeletehandler: We added a combined handler foronDeleteNodesandonDeleteEdgesto make it easier to react to deletions.onBeforeDeletehandler: With this handler you can prevent/ manage deletions.isValidConnectionprop: This makes it possible to implement one validation function for all connections. It also gets called for programmatically added edges.autoPanSpeedprop: For controlling the speed while auto panning.- Background component: add 
patternClassNameprop to be able to style the background pattern by using a class name. This is useful if you want to style the background pattern with Tailwind for example. onMovecallback gets triggered for library-invoked viewport updates (like fitView or zoom-in)deleteElementsnow returns deleted nodes and deleted edges- add 
originattribute for nodes - add 
selectableattribute for edges - Node Resizer: child nodes don’t move when the group is resized, extent and expand is recognized correctly
 - Correct types for 
BezierEdge,StepEdge,SmoothStepEdgeandStraightEdgecomponents - New edges created by the library only have 
sourceHandleandtargetHandleattributes when those attributes are set. (We used to passsourceHandle: nullandtargetHandle: null) - Edges do not mount/unmount when their z-index change
 - connection line knows about the target handle position so that the path is drawn correctly
 nodeDragThresholdis 1 by default instead of 0- a better selection box usability (capture while dragging out of the flow)
 - add 
selectable,deletable,draggableandparentIdtoNodeProps - add a warning when styles not loaded
 

Layouting example for Entitree Flex
We add a new layouting algorithm to our example lineup with the addition of Entitree Flex. This algorithm is similar to d3-hierarchy but allows for sibling nodes as well as nodes with different dimensions.
This example was very kindly contributed by GitHub user @kaustubhxd , thanks Kaustubh! Check it out below.
import React, { useCallback } from 'react';
import {
  Background,
  ReactFlow,
  addEdge,
  ConnectionLineType,
  Panel,
  useNodesState,
  useEdgesState,
} from '@xyflow/react';
 
import '@xyflow/react/dist/style.css';
 
import CustomNode from './CustomNode';
import { initialTree, treeRootId } from './initialElements';
import { layoutElements } from './layout-elements';
 
const nodeTypes = {
  custom: CustomNode,
};
 
const { nodes: layoutedNodes, edges: layoutedEdges } = layoutElements(
  initialTree,
  treeRootId,
  'TB',
);
 
const LayoutFlow = () => {
  const [nodes, setNodes, onNodesChange] = useNodesState(layoutedNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(layoutedEdges);
 
  const onConnect = useCallback(
    (params) =>
      setEdges((eds) =>
        addEdge({ ...params, type: ConnectionLineType.SmoothStep, animated: true }, eds),
      ),
    [],
  );
  const onLayout = useCallback(
    (direction) => {
      const { nodes: layoutedNodes, edges: layoutedEdges } = layoutElements(
        initialTree,
        treeRootId,
        direction,
      );
 
      setNodes([...layoutedNodes]);
      setEdges([...layoutedEdges]);
    },
    [nodes, edges],
  );
 
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
      connectionLineType={ConnectionLineType.SmoothStep}
      fitView
      nodeTypes={nodeTypes}
    >
      <Panel position="top-right">
        <button className="xy-theme__button" onClick={() => onLayout('TB')}>
          vertical layout
        </button>
        <button className="xy-theme__button" onClick={() => onLayout('LR')}>
          horizontal layout
        </button>
      </Panel>
      <Background />
    </ReactFlow>
  );
};
 
export default LayoutFlow;
Devtools and a fresh overview example
Sometimes it’s hard to understand what’s going on in your React Flow app. That’s why we’ve added a devtools section to the docs. It’s a copy pastable example that explains how you can get some insights into your React Flow app. We also published a revised version of the feature overview example.
Check it out below!
import React, { useCallback } from 'react';
import {
  ReactFlow,
  addEdge,
  MiniMap,
  Controls,
  Background,
  useNodesState,
  useEdgesState,
} from '@xyflow/react';
 
import '@xyflow/react/dist/style.css';
 
import {
  nodes as initialNodes,
  edges as initialEdges,
} from './initial-elements';
 
import AnnotationNode from './AnnotationNode';
import ToolbarNode from './ToolbarNode';
import ResizerNode from './ResizerNode';
import CircleNode from './CircleNode';
import TextInputNode from './TextInputNode';
import ButtonEdge from './ButtonEdge';
 
const nodeTypes = {
  annotation: AnnotationNode,
  tools: ToolbarNode,
  resizer: ResizerNode,
  circle: CircleNode,
  textinput: TextInputNode,
};
 
const edgeTypes = {
  button: ButtonEdge,
};
 
const nodeClassName = (node) => node.type;
 
const OverviewFlow = () => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  const onConnect = useCallback(
    (params) => setEdges((eds) => addEdge(params, eds)),
    [],
  );
 
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
      fitView
      attributionPosition="top-right"
      nodeTypes={nodeTypes}
      edgeTypes={edgeTypes}
    >
      <MiniMap zoomable pannable nodeClassName={nodeClassName} />
      <Controls />
      <Background />
    </ReactFlow>
  );
};
 
export default OverviewFlow;

We finally made an editable edge Pro example
One of the most common questions we get from users is how to let users edit an edge’s path. This Pro example demonstrates how to do exactly that, by cutting up an edge into segments that can be freely moved around.
We hope folks will find this example and use the same technique to implement features like freeform edge drawing or algorithmic edge routing.
This is a Pro example. Get all pro examples, templates, 1:1 support from the xyflow team and prioritized Github issues with a React Flow Pro subscription.

React Flow 12 is finally here
React Flow 12 is finally here We are super excited and hope you enjoy the new features as much as we do. The big topics for version 12 are:
- Support for SSG/ SSR: you can now render flows on the server
 - Computing flows: new hooks and helper functions to simplify data flows
 - Dark mode: a new base style and easy way to switch between built in color modes
 - Better DX with TSDoc: we added TSDoc to improve the developer experience
 
If you want to migrate from 11 to 12 or check out the new features, please refer to the migration guide.

New multi-connection line example!
Quite a while back, a user opened a GitHub issue asking us to add the ability to draw multiple connection lines to the library. We don’t have any plans to add this to the library itself, but we hope this example helps folks who need this functionality in their own apps. Check it out here.
import { useCallback } from 'react';
import {
  ReactFlow,
  Background,
  useNodesState,
  useEdgesState,
  addEdge,
} from '@xyflow/react';
 
import '@xyflow/react/dist/style.css';
 
import ConnectionLine from './ConnectionLine';
 
const initialNodes = [
  {
    id: 'a',
    type: 'input',
    data: { label: 'Click to select' },
    position: { x: 100, y: -100 },
  },
  {
    id: 'b',
    type: 'input',
    data: { label: 'these nodes' },
    position: { x: 300, y: -50 },
  },
  {
    id: 'c',
    type: 'input',
    data: { label: 'then drag... ' },
    position: { x: 150, y: 0 },
  },
  {
    id: 'd',
    type: 'output',
    data: { label: '...and connect to me!' },
    position: { x: 250, y: 200 },
  },
];
 
const ConnectionLineFlow = () => {
  const [nodes, _, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
  const onConnect = useCallback(
    ({ source, target }) => {
      return setEdges((eds) =>
        nodes
          .filter((node) => node.id === source || node.selected)
          .reduce(
            (eds, node) => addEdge({ source: node.id, target }, eds),
            eds,
          ),
      );
    },
    [nodes],
  );
 
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      connectionLineComponent={ConnectionLine}
      onConnect={onConnect}
      fitView
      fitViewOptions={{
        padding: 0.2,
      }}
    >
      <Background />
    </ReactFlow>
  );
};
 
export default ConnectionLineFlow;

New node toolbar example!
Buried away in our API reference is the documentation for our
<NodeToolbar /> component. We’ve been missing
an example to accompany it though, so we’ve published a new example to show how
it can be used. Check it out here.
import { useCallback } from 'react';
import {
  Background,
  ReactFlow,
  ReactFlowProvider,
  Panel,
  NodeToolbar,
  Position,
  useNodesState,
} from '@xyflow/react';
 
import '@xyflow/react/dist/style.css';
 
const initialNodes = [
  {
    id: '1',
    position: { x: 0, y: 0 },
    type: 'node-with-toolbar',
    data: { label: 'Select me to show the toolbar' },
  },
];
 
const nodeTypes = {
  'node-with-toolbar': NodeWithToolbar,
};
 
function NodeWithToolbar({ data }) {
  return (
    <>
      <NodeToolbar
        isVisible={data.forceToolbarVisible || undefined}
        position={data.toolbarPosition}
        align={data.align}
      >
        <button className="xy-theme__button">cut</button>
        <button className="xy-theme__button">copy</button>
        <button className="xy-theme__button">paste</button>
      </NodeToolbar>
      <div>{data?.label}</div>
    </>
  );
}
 
function Flow() {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const setPosition = useCallback(
    (pos) =>
      setNodes((nodes) =>
        nodes.map((node) => ({
          ...node,
          data: { ...node.data, toolbarPosition: pos },
        })),
      ),
    [setNodes],
  );
  const setAlignment = useCallback(
    (align) =>
      setNodes((nodes) =>
        nodes.map((node) => ({
          ...node,
          data: { ...node.data, align },
        })),
      ),
    [setNodes],
  );
  const forceToolbarVisible = useCallback((enabled) =>
    setNodes((nodes) =>
      nodes.map((node) => ({
        ...node,
        data: { ...node.data, forceToolbarVisible: enabled },
      })),
    ),
  );
 
  return (
    <ReactFlowProvider>
      <ReactFlow
        nodes={nodes}
        onNodesChange={onNodesChange}
        nodeTypes={nodeTypes}
        fitView
        preventScrolling={false}
      >
        <Panel>
          <h3>Node Toolbar position:</h3>
          <button className="xy-theme__button" onClick={() => setPosition(Position.Top)}>
            top
          </button>
          <button
            className="xy-theme__button"
            onClick={() => setPosition(Position.Right)}
          >
            right
          </button>
          <button
            className="xy-theme__button"
            onClick={() => setPosition(Position.Bottom)}
          >
            bottom
          </button>
          <button className="xy-theme__button" onClick={() => setPosition(Position.Left)}>
            left
          </button>
          <h3>Node Toolbar Alignment:</h3>
          <button className="xy-theme__button" onClick={() => setAlignment('start')}>
            start
          </button>
          <button className="xy-theme__button" onClick={() => setAlignment('center')}>
            center
          </button>
          <button className="xy-theme__button" onClick={() => setAlignment('end')}>
            end
          </button>
          <h3>Override Node Toolbar visibility</h3>
          <label>
            <input
              type="checkbox"
              onChange={(e) => forceToolbarVisible(e.target.checked)}
              className="xy-theme__checkbox"
            />
            <span>Always show toolbar</span>
          </label>
        </Panel>
        <Background />
      </ReactFlow>
    </ReactFlowProvider>
  );
}
 
export default Flow;

The first annual React Flow Developer Survey launches!
We’ve been doing this React Flow thing for a while now and between issues on GitHub and conversations on our Discord server , we’ve learned a lot about what our users want and need from the library. It’s a lot harder to hear about people’s experience with our docs or from the large number of users that might not be actively taking part in our communities, though.
In the past we’ve arranged interviews with some of our Pro subscribers to get an idea of how they use React Flow and the Pro Platform and found the insight invaluable. This year we want to expand that to include as many of our users as possible, so we’ve put together a short survey to help steer our direction going into the new year.
It should only take a few minutes to complete and we’d really appreciate it if you could find the time to fill it out. You can find the survey here and we’ll be publishing the results early in the new year!


React Flow Pro Platform goes open source!

We fund our open source libraries with React Flow Pro subscriptions. Subscribers get access to our Pro Platform where they can view advanced examples, contact us for 1:1 support, and help us prioritize GitHub issues. So far that code has been private but we’ve rebuilt it from the ground-up, added features, refreshed the design, and gave it the MIT License it deserves.
It’s not plug-and-play at the moment, but we hope that some folks take a look, get inspired for their own projects, and that our Pro Subscribers like the new features we built.

New custom edges guide!
We’ve added a new guide to show folks how to create their own custom edges. This
guide breaks down what the <BaseEdge />
and <EdgeLabelRenderer />
components are for, and shows how to use some of the
path utilities React Flow provides.
You can check it out in the customization section of our learning resources here.

New release 11.10.0!
We want to make the migration for v12 as smooth as possible. That’s why we added deprecation warnings for the following util functions:
Rename useReactFlow.project to useReactFlow.screenToFlowPosition
⚠️ changes: no need to subtract react flow bounds anymore!
before:
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
 
const position = reactFlowInstance.project({
  x: event.clientX - reactFlowBounds.left,
  y: event.clientY - reactFlowBounds.top,
});after:
const position = reactFlowInstance.screenToFlowPosition({
  x: event.clientX,
  y: event.clientY,
});Rename getTransformForBounds to getViewportForBounds
⚠️ changes: returns { x: number, y: number, zoom: number } instead of [number, number, number].
before:
const [x, y, zoom] = getTransformForBounds(bounds, width, height, 0.5, 2);after:
const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2);Rename getRectOfNodes to getNodesBounds
no changes, just a renaming.
New features
- added 
useReactFlow.flowToScreenPositionfor completion 
Besides that we fixed some bugs 🐛 You can find all change in the v11.10.0 Github release .

New "prevent connection cycles" example!
The “Prevent connection cycles” example shows how to use the
getOutgoers util to check if a new
connection would cause a cycle in the flow. Check it out here.
import React, { useCallback } from 'react';
import {
  ReactFlow,
  Background,
  useNodesState,
  useEdgesState,
  addEdge,
  getOutgoers,
  useReactFlow,
  ReactFlowProvider,
} from '@xyflow/react';
 
import '@xyflow/react/dist/style.css';
 
import {
  nodes as initialNodes,
  edges as initialEdges,
} from './initialElements';
 
const Flow = () => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
 
  const { getNodes, getEdges } = useReactFlow();
 
  const isValidConnection = useCallback(
    (connection) => {
      // we are using getNodes and getEdges helpers here
      // to make sure we create isValidConnection function only once
      const nodes = getNodes();
      const edges = getEdges();
      const target = nodes.find((node) => node.id === connection.target);
      const hasCycle = (node, visited = new Set()) => {
        if (visited.has(node.id)) return false;
 
        visited.add(node.id);
 
        for (const outgoer of getOutgoers(node, nodes, edges)) {
          if (outgoer.id === connection.source) return true;
          if (hasCycle(outgoer, visited)) return true;
        }
      };
 
      if (target.id === connection.source) return false;
      return !hasCycle(target);
    },
    [getNodes, getEdges],
  );
 
  const onConnect = useCallback((params) =>
    setEdges((els) => addEdge(params, els)),
  );
 
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
      isValidConnection={isValidConnection}
      fitView
    >
      <Background />
    </ReactFlow>
  );
};
 
export default () => (
  <ReactFlowProvider>
    <Flow />
  </ReactFlowProvider>
);
We refreshed our docs!
We refreshed the React Flow docs in November 2023, so things might look a little different around here:
- 
Docs are now called Learn. This section aims to answer the question of “how do I use X?”
 - 
API is now called Reference. This section answers the question “what is this thing?” A big change from the previous version of our docs are that all of our types, components, hooks, and util functions now get their own page now.
 - 
“How to” blog posts now live in Learn > Tutorials
 
Why the changes?
So far the docs have been growing organically since 2019, without any sort of overarching concept. While we worked on a website redesign, we decided it was time to rethink how folks are using our docs so that we can create a better developer experience. Our hope is that these changes make the docs easier to use for both experienced React Flow users and newcomers.
We also did a change of tech stack along the way. We were using Docusaurus, and now we’re using Nextra . Cool beans.
If you find anything to change or improve, just click on the “Edit this page” link on the right-side of any page in our docs or open an issue over on GitHub .