Has anyone attempted a dashflow component from Reactflow?

Hi all

Found this interesting react package and I can easily imagine as part of the Dash tools

https://reactflow.dev/

I have attempted to follow the “create your own components” wrapping up a react package and I got lost in the documentation,
Also noting some of the latest npm package not quite aligned with the list of the directions in setting up
There is also this latest reference that i tried to follow:

https://community.plotly.com/t/creating-custom-dash-components/72547/6

But the resulting template following this latest direction is nowhere near the initial template to follow the original documentation, reactflow has also quite a few features to bring and I got lost in several attempts to make it work.

Could this be something in line of incorporation by some skilled community members here? I am just a python hobbyist loving the Dash universe

Cheers!

Hi,

I attempted to create a dash component from reactflow, the basic node and edge creation just works fine but I got stuck in creating custom node and edges in reactflow.

My repository for dash reactflow : GitHub - siddharthajuprod07/dash-react-flow

The main issue I am facing is when I pass a dash component (like dcc.checkbox etc) as part of the custom node react is not able to identify it as a component and not rendering it.

I am following the same guide mentioned in reactflow custom node (Custom Nodes Guide - React Flow)

I have develop the code to handle the components passed from dash app (https://github.com/siddharthajuprod07/dash-react-flow/blob/master/src/ts/utils/customNode.tsx) , but its throwing me error.

import React, { useCallback } from 'react';
import { Handle, Position } from 'reactflow';


function CustomNode({ data, isConnectable }) {
  const dashComponentList:React.ReactNode[] = data["dashComponents"]
  console.log(dashComponentList)

  function createReactComponent(dashComponent:React.ReactNode,i:number){
    const NewComponent = dashComponent["namespace"]
    return <NewComponent key={i} type={dashComponent["type"]} {...dashComponent["props"]}></NewComponent>
  }
  
  return (
      <div className="custom-node">
        <Handle type="target" position={Position.Top} isConnectable={isConnectable} />
        {dashComponentList.map((dashComponent,i) => createReactComponent(dashComponent,i))} 
        <Handle type="source" position={Position.Bottom} isConnectable={isConnectable} />
      </div> 
  );
}

export default CustomNode;

Can anybody give me any direction on how to pass dash components to react to identify it as a component and render it?

Thanks,
Sid

@snehilvj will you be able to provide some guidence here please.

With the influx of new code generation tools (specifically the new Claude Sonnet 3.5 v2), wonder if it’s somewhat easier to port react libraries to plotly dash as components? If so, hopefully we can bring react-flow to plotly dash

@Sid Were you able to resolve the error you were facing?

Echoing what @monitorcasalab said, these component would be a great addition to Dash. @AnnMarieW @jinnyzor @snehilvj Any help would be greatly appreciated.

Its very easy to build components with Claude try it yourself, created a video a week or two ago on this subject that you could use as a guide.

1 Like

I was actually also thinking of making it a component. It’s somewhat on the list but still other parts which are more urgent, but I do think it has many features we like.

I did convert some smaller parts before, maybe I will use @PipInstallPython guide and work on this :smiley: But happy to join hands here

So I followed the video by @PipInstallPython (thank you so much for this btw!) and was able to get a basic react flow component to run.

Next, I want to implement the whole reactflow library and converted their entire documentation and reference API into PDFs. But the issue is that I have a free Claude.AI account and I am hitting “conversation over length limit” errors when trying to attach the PDFs.

Placing the PDFs here if someone wants to utilize:
https://drive.google.com/drive/folders/11l1x7MWpE920cBjnt1VQKF90AZpfJSvL?usp=sharing

Do drop an update if able to make progress with this. @PipInstallPython @simon-u

1 Like

Thats awesome! Thanks for the update it made my day, happy the video helped and its look really good! I can see this being a really useful component and its nice to see other component builders starting their journey and building useful tools for this great framework :smiley:

@hkhare , do you have a repo to share? Then I can see what you already have and can start from there

I have it here: GitHub - hkhare42/dash-flow-dev: dash component based on react flow but I’ve managed to break something trying to implement custom edges, custom nodes and dagre layouting. Figuring it out. Feel free to fork.

Your layout looks somewhat wrong, not sure what this folder is. Assuming you messed up and didn’t delete it for some reason?

Gave it a shot and was able to get it working and fixed the errors that are currently visibale in the repo you sent, ended up being a bit different than the approach you went with but I’ll include a demo and reffrence.

import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import {
    ReactFlow,
    Controls,
    MiniMap,
    Background,
    addEdge,
    ReactFlowProvider,
    applyNodeChanges,
    applyEdgeChanges
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';

/**
 * Convert Dash components in node data to React elements
 */
const processDashComponents = (nodes) => {
    if (!nodes) return [];
    return nodes.map(node => ({
        ...node,
        data: {
            ...node.data,
            label: node.data.label?.props ? node.data.label : String(node.data.label || '')
        }
    }));
};
/**
 * DashFlow is a Dash component that wraps React Flow to create
 * interactive node-based interfaces. It supports customizable nodes,
 * edges, and various interaction modes.
 */
const Flow = (props) => {
    const {
        id,
        nodes,
        edges,
        nodesDraggable,
        nodesConnectable,
        elementsSelectable,
        nodeTypes,
        edgeTypes,
        showMiniMap,
        showControls,
        showBackground,
        style,
        className,
        setProps
    } = props;

    // Process nodes to handle Dash components
    const processedNodes = processDashComponents(nodes);

    const onNodesChange = useCallback((changes) => {
        // Use applyNodeChanges helper from React Flow to correctly update nodes
        const nextNodes = applyNodeChanges(changes, nodes);
        setProps({ nodes: nextNodes });
    }, [nodes, setProps]);

    const onEdgesChange = useCallback((changes) => {
        // Use applyEdgeChanges helper from React Flow to correctly update edges
        const nextEdges = applyEdgeChanges(changes, edges);
        setProps({ edges: nextEdges });
    }, [edges, setProps]);

    const onConnect = useCallback((connection) => {
        if (!connection.source || !connection.target) return;
        const newEdge = {
            id: `e${connection.source}-${connection.target}`,
            ...connection
        };
        setProps({ edges: [...edges, newEdge] });
    }, [edges, setProps]);

    // Default container style with mandatory height
    const containerStyle = {
        width: '100%',
        height: '600px',  // Set a default height
        ...style
    };

    return (
        <div id={id} style={containerStyle} className={className}>
            <ReactFlow
                nodes={processedNodes}
                edges={edges}
                onNodesChange={onNodesChange}
                onEdgesChange={onEdgesChange}
                onConnect={onConnect}
                nodesDraggable={nodesDraggable}
                nodesConnectable={nodesConnectable}
                elementsSelectable={elementsSelectable}
                nodeTypes={nodeTypes}
                edgeTypes={edgeTypes}
                fitView
                deleteKeyCode={['Backspace', 'Delete']}
                panOnScroll
                selectionOnDrag
                panOnDrag={[1, 2]}
                zoomOnScroll
                snapToGrid
            >
                {showControls && <Controls />}
                {showMiniMap && <MiniMap />}
                {showBackground && <Background />}
            </ReactFlow>
        </div>
    );
};


// Main component that wraps Flow with ReactFlowProvider
const DashFlow = (props) => {
    return (
        <ReactFlowProvider>
            <Flow {...props} />
        </ReactFlowProvider>
    );
};

DashFlow.defaultProps = {
    nodesDraggable: true,
    nodesConnectable: true,
    elementsSelectable: true,
    showMiniMap: true,
    showControls: true,
    showBackground: true,
    nodes: [],
    edges: [],
    style: {},
    className: ''
};

DashFlow.propTypes = {
    /**
     * The ID used to identify this component in Dash callbacks.
     */
    id: PropTypes.string,

    /**
     * Array of node objects with position, data, and optional style information
     */
    nodes: PropTypes.arrayOf(PropTypes.shape({
        id: PropTypes.string.isRequired,
        position: PropTypes.shape({
            x: PropTypes.number.isRequired,
            y: PropTypes.number.isRequired
        }).isRequired,
        data: PropTypes.object.isRequired,
        type: PropTypes.string,
        style: PropTypes.object
    })),

    /**
     * Array of edge objects defining connections between nodes
     */
    edges: PropTypes.arrayOf(PropTypes.shape({
        id: PropTypes.string.isRequired,
        source: PropTypes.string.isRequired,
        target: PropTypes.string.isRequired,
        type: PropTypes.string,
        animated: PropTypes.bool,
        style: PropTypes.object
    })),

    /**
     * Enable/disable node dragging
     */
    nodesDraggable: PropTypes.bool,

    /**
     * Enable/disable creating new connections
     */
    nodesConnectable: PropTypes.bool,

    /**
     * Enable/disable selection
     */
    elementsSelectable: PropTypes.bool,

    /**
     * Custom node type components
     */
    nodeTypes: PropTypes.object,

    /**
     * Custom edge type components
     */
    edgeTypes: PropTypes.object,

    /**
     * Show/hide minimap
     */
    showMiniMap: PropTypes.bool,

    /**
     * Show/hide controls
     */
    showControls: PropTypes.bool,

    /**
     * Show/hide background
     */
    showBackground: PropTypes.bool,

    /**
     * Custom style for the container div
     */
    style: PropTypes.object,

    /**
     * Custom CSS class name
     */
    className: PropTypes.string,

    /**
     * Dash-assigned callback that should be called to report property changes
     * to Dash, to make them available for callbacks.
     */
    setProps: PropTypes.func
};

// Add this to register the component name
DashFlow.displayName = 'DashFlow';

export default DashFlow;

My advice would be together all the notable project knowledge you can acquire. I scrubbed all Quickstart - React Flow, Api Reference - React Flow and React Flow.

Then I asked it to build me a roadmap.md for the project and used it for custom instructions for project Then just asked questions like in the video tuttorial.

Thanks for sharing.

Yeah don’t know how or why that folder is there but I let it stay since I didn’t want to mess with the boilerplate structure. It’s probably there because of an erroneous run.

Main component code is at : dash-flow-dev/dash_flow/src/lib/components at main · hkhare42/dash-flow-dev · GitHub

The simple node-edge setup worked for me. It’s when I started to implement custom nodes, custom edges and dagre layouting that I ran into problems. And all of these three are essential for what I’m working on. Something that looks like:

Looking forward to your demo / reference to learn more.

Not entirely to that point in the image you shared. Current limitations are it only supporting html components within nodes. Was working on a way to other dash components to render into nodes but wasn’t able to fully figure it out. Along with not being able to figure out edge animations like in Animating Edges - React Flow

I did set this build up with a mini map prop, debug tool and was able to get resizable nodes working.

1 Like