Using Flexbox Layout to Arrange Diagram Components in React

This tutorial demonstrates how to use the flexbox layout to arrange the various diagram controls that come with the diagram library for React. The controls we will arrange are DiagramView , NodeListView , Ruler , Overview, Zoomer and Ruler. This is a screenshot of the final application:

We build our project using the React framework and MindFusion diagram library for React available from

I. Initial Project Setup

We open a terminal and navigate to the folder where we want to create our application. We use create-react-app to initialize an empty React application:

npx create-react-app flex-diagram

As you we have named our application flex-diagram. Once the initial React setup is complete, we install the diagram:

npm install diagram-library-react

Once we are done with that we can start coding our application. We add a new JavaScript file, which we name DiagramApp.js. In it we first import the default React namespace and declare a member import of the Component class. Then we declare default import of MindFuson’s diagram library under the name ‘mf’. Finally, we declare member imports of the control classes we intend to use: DiagramView, Overview, NodeListView, ZoomControl and Ruler:

import React, { Component } from 'react';
import mf from 'diagram-library';
import { DiagramView, Overview, NodeListView, ZoomControl, Ruler } from 'diagram-library-react';

Then we can create our class DagramApp, which extends component. We will need a constructor, so we declare one. In it we create an instance of the Diagram class, which represents the diagram. Note that this is not the DiagramView for React class, which renders the diagram. This is the interactive, diagram, which is actually rendered by DiagramView.

class DiagramApp extends Component {
  constructor(props) {

    // create the diagram
    var diagram = new mf.Diagramming.Diagram();

Then we create an array of ShapeNode instances, which will be used by the NodeListView control. Again, the NodeListView is a UI component that renders the nodes, but it does not create them. They are provided to it as a parameter.

var nodes = [];
    var shapes = ["Actor", "RoundRect", "Triangle", "Decision"];
    for (var i = 0; i < shapes.length; ++i) {
      var node = new mf.Diagramming.ShapeNode(diagram);


We create an array just with the id-s of the ShapeNode -s, which we will use as labels for them as well. You can check the id-s of the available predefined ShapeNode -s at

Finally, we need to store the diagram, together with the nodes and the shape id-s in the React state. We will need them when we create the HTML for our application. In React, the way to access class variables is to store them in the state.

    this.state = {
      diagram: diagram,
      nodes: nodes,
      captions: shapes

II. Arranging the UI with CSS and the Flexbox Layout

Our flexbox layout has this structure:

We have colored the different areas of the page in different colors to show you the sections in the flexbox layout. The main container takes 100% of the space e.g. the whole page. We fix its height to be at least 500px. The layout of the flexbox is row without wrap, which means that the elements will not be rearranged in severa rows by resize. That is exactly what we need. Here is the code of the container style:

  display: flex;
  flex: 1 1 100%;
  min-height: 500px;
  flex-flow: row nowrap;
  background-color: azure;

The first item in the container is the vertical column where we want to place the Overview and NodeListView controls under each other. This column needs to stay fixed size. We do not want it resized when the user resizes the page. It is the diagram in the middle that must be resized when the available space changes. We call the column “left-sidebar” and set its ‘flex-flow’ to column. We use again no wrap to stop the layout placing the two controls next to each other, if the available space gets too short. We also fix the width of this element to 200 pixels, which suits our controls fine.

  flex: 0 0 200px;
  display: flex;
  flex-flow: column nowrap;
  background-color: beige;

There is difference in how we want the Overview an NodeListView controls to take space. The overview requires fixed amount of space. We want the extra space to be given to the NodeListView. That is why we add one more style to be applied to it:

.item {
  align-self: stretch;
  flex: 1 1 300px;  

We give 1 as a value to flex-grow and flex-shrink, indicating that we expect this element to get resized rather than the other items in the right column.

We are ready to deal with the diagram now, which is in the middle. Here it is important to indicate that this element will stretch to take all the available place. Moreover, when the space gets smaller, it is this item that must shrink:

.center-area {
     align-self: stretch;
     flex: 10 10 500px;
     max-height: 800px;
     overflow: hidden;

We set big values to the flex-grow and ‘flex-shrink’ attributes and set the flex-basis to 500 px. We must restrict the height of the diagram to 800px, because it could get really long. Important attribute it ‘align-self’, which is applied to items arranged by flexbox containers, not to the container itself. Here we use this attribute to tell the diagram to stretch itself, when space is available. The overflow attribute is hidden to avoid rendering of needless scrollbars in large diagrams.

Finally, the right sidebar will host the Zoom control. It is similar to the left sidebar, but it does not have a ‘special’ item such as the NodeListView. The Zoom control is a UI control with fixed size and does not need special handling. We just need to make sure no extra space is diverted to it, if the window gets too big:

  flex: 0 0 50px;
  background-color: lavender;  

And that was the last style for the last element that we need to define. Now we are ready to apply those styles to the real React components and arrange them.

III. The ‘render’ Method

The first thing we declare in the ‘render’ method of our new DiagramApp React component are some properties:

 var props = {
      "id": "diagram1",
      "linkHeadShapeSize": 2,
      "routeLinks": true,
      "roundedLinks": true,
      "backBrush": "#e0e9e9"

These are properties for the Diagram instance and we will provide them through the JavaScrpt spread operator. Then in the return statement we first declare the container div element. Its style is “container”. In it we declare the left sidebar, which will hold the overview and the NodeListView. We declare them as well:

return (      

        <div className="container">
            <div className="left-sidebar">
              <Overview diagram={this.state.diagram}></Overview>  
  		<NodeListView className="item" 



The Overview is bound to the diagram, which we keep in the state object. The NodeListView requires list with the nodes and captions, if we want to have captions over nodes. We want and we have stored the nodes and the captions in state as well.

After that is turn for the diagram. It will take the central area and its class is ‘center-area’. In addition to Diagram, we will use the Ruler control as well. We place it first and nest the diagram inside it. We use the spread operator to assign to the diagram the properties, which we have initialize at the beginning of the method.

<div className="center-area">              
            <Ruler style={{ width: "100%", height:"800px" }}>
                <DiagramView diagram={this.state.diagram} 

Finally, we declare the right sidebar, which contains the Zoom control. The Zoom control also needs to be bound to a diagram instance and we use state to get reference to our diagram:

          <div className="right-sidebar">
          <ZoomControl diagram={this.state.diagram}></ZoomControl>        

With that our component is ready. We need only to place it in index.js instead of the default App Component:

import DiagramApp from './DiagramApp';


We can run the sample with

npm start

Then you can see your application on port 3000 on localhost.

You can download the full code structured as npm project from this link:

Download Full Source Code

For technical question, please use the JS Diagram forum:

About Diagramming for JavaScript: This native JavaScript library provides developers with the ability to create and customize any type of diagram, decision tree, flowchart, class hierarchy, graph, genealogy tree, BPMN diagrams and much more. The control offers rich event set, numerous customization options, animations, graph operations, styling and themes. You have more than 100 predefined nodes, table nodes and more than 15 automatic layout algorithms. Learn more about Diagramming for JavaScript at

Logic Model Software Demo

The logic model is a tool that helps managers evaluate the effectiveness of a program. The tool allows the user to list the input, output and outcomes of the process.

Logic Model Software Demo

Logic Model Software Demo

In our sample we have used the WinForms Diagram Control to create a sample software that lets users:

  • drag and drop tables that represent popular items in each of the three sections of the logic mode: input, output and outcomes;
  • edit the tables: add and delete rows, edit the text on rows;
  • connect table rows to illustrate the process flow.

I. Project Setup

We create a new project in Visual Studio and name it “LogicModel”. We add references to the following diagramming libraries:

MindFusion Libraries Used by the Logic Model Software

MindFusion Libraries Used by the Logic Model Software

After that we drag and drop the NodeListView control from the Toolbox and set its IconSize property to Size(50,50). This property tells the control how big the items in the NodeListView should be rendered.

nodeListView1.IconSize = new System.Drawing.Size(50, 50)

Then we drag and drop a DiagramView object that creates automatically a Diagram instance that represents the diagram. Here we need to set the AllowDrop and AllowInplaceEdit properties to “true”. This means the diagram can create new nodes from the items in the NodeListView that are dropped onto it. Then it allows the user to edit the nodes e.g. modify the text in the table cells:

this.diagramView1.AllowDrop = true;
this.diagramView1.AllowInplaceEdit = true;

Last but not least we set the Resize mode of the DiagramView to Fill, which means it will occupy all available space when the user changes the size of the application window.

II. The NodeListView

It holds TableNode instances that represent items in the logic model. Let’s look at a simple table. The first table called “Investment”. Here are the first three lines of code for it:

//the table with resources
TableNode tbResources = new TableNode();
tbResources.RedimTable(2, 4);
tbResources.Caption = "Investment";

The RedimTable method changes the number of rows and columns of the TableNode to be the ones specified as arguments. Each of the tables in the logic model has two columns – one for a bullet and one for the label. The count of rows varies.

Then we edit the text that is rendered by this TableNode:

tbResources[1, 0].Text = "People";
tbResources[1, 1].Text = "Money";
tbResources[1, 2].Text = "Technology";
tbResources[1, 3].Text = "Space";

Now is time for some styling. We set the Pen for the table, the pen for the caption and the CaptionBackBrush:

tbResources.Pen = new MindFusion.Drawing.Pen(Color.FromArgb(192, 192, 192));

tbResources.CaptionBrush = new MindFusion.Drawing.SolidBrush(Color.White);
tbResources.CaptionBackBrush = new MindFusion.Drawing.SolidBrush(Color.FromArgb(247, 150, 70));

Then we set the background of the rest of the TableNode:

tbResources.Brush = new LinearGradientBrush(Color.FromArgb(252, 213, 181), Color.FromArgb(248, 234, 223));

Each diagram item has a Tag property. This useful property holds any information you find useful. It is of type Object and you can use it to store data used by your node. In our application we use the Tag property of a TableNode to store the URL to the bullet rendered before each of its labels:

//keep the bullet as a tag
tbResources.Tag = Image.FromFile("../../Resources/orange.png");
//set an orange bullet before each label

for (int i = 0; i < tbResources.Rows.Count; i++)
        tbResources[0, i].Image = Image.FromFile("../../Resources/orange.png");
        //save the row index as a tag for cells with text
        tbResources[1, i].Tag = i;

Then we use the Tag property of the TableNode.Cell objects to store their row index. We will use it later when we handle events.

Finally, let’s not forget to add the new TableNode to the NodeListView:


The other tables are created in a similar way.

III. The Containers

The three rectangles where users drop tables are ContainerNode-s. These are special kinds of DiagramNode -s that can hold other nodes. Once placed into them, the containing nodes move with the container. Containers can resize automatically to fit all items but in our case we will forbid this.

Here is the code that creates the third container – “Outcomes”:

//the last container
ContainerNode cOutcomes = diagram1.Factory.CreateContainerNode(0, 0, 20, 20);
cOutcomes.Tag = 2;
cOutcomes.Caption = "Outcomes";

Note that we use again the Tag property this time to keep the index of the container – first, second or third e.g. 0, 1 or 2. Then we add some styling using the Pen, CaptionBrush, CaptionBackBrush and Brush properties to define the background and border of the container and its caption:

cOutcomes.Pen = new MindFusion.Drawing.Pen(Color.FromArgb(80, 80, 80));
cOutcomes.CaptionBrush = new MindFusion.Drawing.SolidBrush(Color.FromArgb(80, 80, 80));
cOutcomes.CaptionBackBrush = new MindFusion.Drawing.SolidBrush(Color.FromArgb(168, 192, 120));
cOutcomes.Brush = new LinearGradientBrush(Color.FromArgb(209, 224, 180), Color.FromArgb(235, 238, 229));

Then we set some properties that define how the ContainerNode responds to new items being added or removed:

cOutcomes.AllowAddChildren = true;
//do not allow the container to change size or be folded
cOutcomes.AutoGrow = false;
cOutcomes.AutoShrink = false;
cOutcomes.Foldable = false;

We let the container accept new children and do not allow the user to fold, which means to collapse it.

The containers are sized relatively to the client area of the DiagramView:

//resize the containers according to the current size of the diagramView
private void resizeContainers()
    //convert the size of the rectangle from client measure units to diagram units
    RectangleF viewRect = diagramView1.ClientToDoc(diagramView1.ClientRectangle);

First we convert the size of the DiagramView to diagram units calling the ClientToDoc method. Then we need to find the ContainerNode -s of the diagram and arrange them next to each other. When we do this we use the Tag property of each container that tells us which is the order of the container and where we should pace it:

//identify the containers
foreach (DiagramNode node in diagram1.Nodes)
       ContainerNode c = node as ContainerNode;

       if (c != null)
          //get the index that tells us if this is the first, second or third container
          int index = (int)c.Tag;
          //relocate the container rectangle based on its index
          c.Bounds = new RectangleF(viewRect.Left + viewRect.Width * (0.02F + index * 0.34F),
          viewRect.Top + viewRect.Height * 0.02F, viewRect.Width * 0.27F, viewRect.Height * 0.96F);

We call this method each time the DiagramView is resized by handling the ClientSizeChanged event:

//raised when the size of the ClientRectangle has changed.
private void diagramView1_ClientSizeChanged(object sender, EventArgs e)
    //adjust the size of the containeres

IV. Diagram Events

We handle the NodeCreated diagram event each time the user drops a new node from the NodeListView onto any of the ContainerNode-s:

this.diagram1.NodeCreated += new System.EventHandler(this.diagram1_NodeCreated);

The method that handles the event should do three important things: 1) resize the new TableNode so all text fits into it; 2)assign to each cell its correct Tag (e.g. row index) and 3) find the ContainerNode onto which the TableNode was placed and add it to it. Here is the first part of the method:

//raised when the user has dropped a new TableNode
private void diagram1_NodeCreated(object sender, NodeEventArgs e)
     TableNode tNode = e.Node as TableNode;

    if (tNode != null)
        //adjust the node size
        //arrange the tags for the table cells

The resizeNode and arrangeTags methods adjust the size of the TableNode and assign to each cell in the second column of the node its row index as a Tag. We won’t list the methods here, you can check them in the source code available for download.

We find the ContainerNode, if any onto which the TableNode was placed by checking if its top left corner is inside the container:

//find out the container onto which the node was dropped, if any
foreach (DiagramNode diagramNode in diagram1.Nodes)
    if (diagramNode.ContainsPoint(e.Node.Bounds.Location))
       ContainerNode container = diagramNode as ContainerNode;
       if (container != null)
         //add the new node to its container

If it is within the container we add the node.

V. Context Menu

The context menu is rendered at right mouse click. We handle the CellClicked event of a diagram to show it:

//tracks when the user clicks on a table cell
diagram1.CellClicked += new EventHandler(diagram1_CellClicked);

We also declare a global TableNode.Cell clickedCell variable that keeps track of the clicked cell. We will use the data later:

//keeps the cell the user has clicked on
TableNode.Cell clickedCell = null;

In the diagram1_CellClicked event we check if the right mouse button was clicked and then show a ContextMenuStrip object:

//handles the cellClicked event
void diagram1_CellClicked(object sender, CellEventArgs e)
    //if the user has clicked with the right mouse button
    if(e.MouseButton == MouseButton.Right)
        //we should keep track of the clicked cell
        clickedCell = e.Cell;
        //and show the context menu

We handle the ItemClicked event of the ContextMenuStrip:

if (clickedCell != null)
      TableNode tNode = clickedCell.Table;

      //if the user has selected to add a row
      if (e.ClickedItem.Text.Equals("Add row"))
            //add a row
            //assign the image URL kept as a tag to the first cell in the new row
            tNode[0, tNode.Rows.Count - 1].Image =
                 tNode.Tag as Image;
            //type in some dummy text in the text cell
            tNode[1, tNode.Rows.Count - 1].Text = "[edit text]";               

In the first part of the method we handle the case when the user has chosen to add a new row. The new row is inserted at the end of the table with the AddRow method. We use the Tag property of the TableNode which points to the location of the bullet for this table and we render it to the first cell of the new row.
If the user wants to delete a row we show first a warning message. Here we render the name of the detected row to be deleted. If the user agrees we get the index of the row using its Tag and we remove it from the TableNode:

 else if (e.ClickedItem.Text.Equals("Delete row"))

          //display a warning, which shows which row is about to be deleted
          string message = "Do you want to delete row " + clickedCell.Text + "?";
          string caption = "Confirm Delete";
          MessageBoxButtons buttons = MessageBoxButtons.YesNo;
          DialogResult result;

          // Displays the MessageBox.
          result = MessageBox.Show(message, caption, buttons);
          //if the user has decided to delete the row
          if (result == System.Windows.Forms.DialogResult.Yes)
             //get the index of the row that is to be deleted
             int rowIndex = (int)clickedCell.Tag;                        

Both actions of delete and insert of a new row require the indices of the table rows to be rearranged and the size of the table to be adjusted. We call:

//adjust the node size
//arrange the table tags

VI. Links

Users can draw links between rows of the tables. To achieve this we first change the default Behavior of the DiagramView :

this.diagramView1.Behavior = MindFusion.Diagramming.Behavior.LinkTables;

Then we add some styling for the links:

//styling the links
diagram1.LinkShape = LinkShape.Cascading;
diagram1.LinkCascadeOrientation = MindFusion.Diagramming.Orientation.Horizontal;
diagram1.LinkHeadShape = ArrowHeads.Triangle;
diagram1.LinkHeadShapeSize = 4;

Here we define the shape of the links as “Cascading” and we change the default LinkHeadShape and LinkHeadShapeSize properties. Further styling of the links is done with a Theme and a DiagramLinkStyle:

//create a theme to apply additional link styling
Theme theme = new Theme();
DiagramLinkStyle style = new DiagramLinkStyle();
style.Brush = new MindFusion.Drawing.SolidBrush(Color.FromArgb(192, 192, 192));
style.Stroke = new MindFusion.Drawing.SolidBrush(Color.FromArgb(80, 80, 80));
theme.RegisterStyle(typeof(DiagramLink), style);
diagram1.Theme = theme;

There we specify the Brush for the links and the Stroke. When new links are created we want them to have 3 segments because this looks good. So, we handle the LinkCreated event to specify this:

this.diagram1.LinkCreated += new System.EventHandler(this.diagram1_LinkCreated);


//raised when the user draws a link between two tableNode-s.
private void diagram1_LinkCreated(object sender, LinkEventArgs e)
    //the link should have 3 segments
    e.Link.SegmentCount = 3;

With this our Logic Mode demo application is ready. The complete code for the application with all necessary libraries of the diagramming component is available for free direct download download from here:

Download the Logic Model Demo Application Source Code

About MindFusion.Diagramming for WinForms: A programming component that provides any WinForms application with a full set of features for creating and customizing all types of diagrams, flowcharts, schemes, hierarchies, trees, graphs etc. The control provides numerous ways to save and load a diagram, six auxiliary controls and more than 15 automatic graph layout algorithms. Diagram elements include scrollable tables, container nodes, multi-segment arrows, custom diagram item types and many more. Further details here.

Diagramming for WinForms is a royalty-free component, clients get 12 month upgrade subscription when buying a license. The source code is also available for purchase. Visit the buy page for a list with the current license prices.

Diagramming for Windows Forms, V6.3 Released

MindFusion has released a new version of Diagramming for WinForms with the following new features:

Map nodes
The new MapNode class represents nodes that can render geographical maps. At this time map nodes can display the content of an Esri shapefile files. The content of a map file is represented by an instance of the MapContent class that should be assigned to the Content property of a MapNode. When the map is associated with a DBF database file, map regions can display labels – further details here.

Map nodes

Map nodes

Import diagrams from SVG
The SvgImporter class allows importing Scalable Vector Graphics files (*.svg) into MindFusion.Diagramming. Each top-level SVG group element is imported as a separate SvgNode, whose Content is set to the group’s child elements.

Visio2013Exporter improvements

  • Support for multi-segment links
  • Bezier links are now exported as NURBS lines
  • Support for rotated nodes
  • Proper scale for all MeasureUnit values
  • Support for semi-transparent colors
It is easy to import a  diagram from Visio.

Import from Visio.


  • You can now set the AutoGrow property to false to prevent containers from resizing automatically
    when they would not fit newly added nodes.
  • The Brush property of LinkLabel class lets you set background color for link labels.
  • Now the NodeModified event is raised after the undo record for that modification has been added to the command history. This makes it easier to merge the ModifyItemCmd with custom commands created from NodeModified handler.
  • and more – read the full list here.

You can read further details about this release at the news page in the Diagramming for WinForms forum. You can download the trial version from the link below:

Diagramming for WinForms, V6.3

If you have questions or run into problems using the component you can use the Diagramming for WinForms forum, the help desk or write us at Our support team will be pleased to help you.

About MindFusion.Diagramming for WinForms: A programming component that provides any WinForms application with a full set of features for creating and customizing all types of diagrams, flowcharts, schemes, hierarchies, trees, graphs etc. The control provides numerous ways to save and load a diagram, six auxiliary controls and more than 12 automatic graph layout algorithms. Diagram elements include scrollable tables, container nodes, multi-segment arrows, custom diagram item types and many more. Further
details here.

Diagramming for WinForms is a royalty-free component, clients get 12 month upgrade subscription when buying a license. The source code is also available for purchase. Visit the buy page for a list with the current license prices.

Diagramming for WPF 3.0.2

MindFusion has just released Diagramming for Wpf programming component v. 3.0.2. Most of the newly added features are requested by our customers. Here are details:

Visio 2003 Import

The new VisioImporter lets you import Visio 2003 XML Drawing files (*.vdx) into WpfDiagram. You can import all standard Visio flowchart shapes as well most of the UML and Database entity shapes. The shapes are imported to their closest representations in the MindFusion.Diagramming for Wpf object model. The relationships between the objects are preserved and the Visio links are imported as DiagramLink objects. Additionally, most of the attributes of the Visio objects such as text, text format, fill and line colour and style are preserved. WpfDiagram raises an event for each imported node and you can set the shape node if it is not recognized by the control or you want to change the shape.

The Import method imports all Visio pages into a DiagramDocument. A DiagramPage is created for each page from the VDX file. The new GetPageCount and ImportPage methods let you determine how many pages are in the Visio document and import only a single one. You can import all Visio pages into a single diagram.

It is easy to import a  diagram from Visio.

It is easy to import a diagram from Visio.


  • The overload methods of AttachTo that attach node to link segments or control points, now let you specify negative index values. Negative values are interpreted as relative to the last point or segment, regardless of the current number of link segments.
  • The handling of Clip paths in PdfExporter is improved.
  • You can export the swimplane grid to Visio by setting the ExportLanes property of the VisioExporter.
  • The Copy method lets you copy text attributes between objects that implement the ITextAttribute interface, such as diagram items table cells, tree items.
  • as well other new features – check the full list here.
An arrow is shaped by its control points.

An arrow is shaped by its control points.

You can download the trial version of the software from this link:

Download MindFusion.Diagramming for WPF 3.0.2

The download contains all runtime libraries of the control, various samples for different .NET versions, extensive desktop documentation and step-by-step tutorials.

If you face difficulties installing or using Diagramming for Wpf, please contact MindFusion support team per e-mail or phone. You can also use the forum or help desk. All support inquiries are answered within hours of receiving them.

About MindFusion.Diagramming for Wpf: Designed and developed to be easy to integrate, use, and customize, this native WPF component places at your disposal every single feature you would ever need to create flowcharts, diagrams, graphs, schemes, DB relationships, trees and many more. Its long list of style options gives you complete control over the appearance of the diagram. With a set of eight automatic layouts you are sure to choose the best arrangement for your items and make the diagram easy to comprehend.

The control boasts a long list of events, properties and methods for user interaction, item creation, data input and output. You can read the full features list here. The online demo shows samples that demonstrate various capabilities of the control. The licensing scheme and prices are uploaded at the buy page. Source code is also available.