Building a Config Driven UI in React - Part 1
Published On: 11/24/2019
reactjs
javascript
ui

This is the first part of the 2 part blog, where I share my experience in putting together a configuration driven user interface.

The solution consisted of the actual UI that is generated by configuration and admin app where a user can drag and drop to build the configuration. This blog specifically talks about how we handled the UI based on a JSON configuration.

TL;DR

We built a configuration driven UI that consisted of 2 parts,

  • One to define the layout, which consisted of a recursive structure to hold vertically and horizontally stacked elements
  • The second being a mapping of the leaf nodes ( using an id ), to define what needs to be displayed in it's place.

The rest of the blog goes into detail on how this was accomplished.

The Problem

Our customer wanted to build an enterprise dashboard to help them see dimensions of data together. Multiple such pages can be built, with different layout depending on the dimension.

Most importantly they wanted minimal or no dependency on developers for any incremental page addition

10,000ft Solution

A part of our solution looked something like below.

Solution Blocks

The DnD Config Generator helped to assemble the UI components together and persist them into a backend The configuration was served to the Config Driven UI component to paint the page as dictated by the JSON.

The Config Driven UI

Logical starting point was to put together the config driven UI first to understand what kind of configuration is required to be generated ( and ofcourse to showcase to the customer their dashboard, which is of higher business value).

So we started to break down our problem and came up with 2 major components.

  • Building the Layout
  • Filling the gaps in the layout with actual values such as titles, visualizations and summary. We call this as an Element.

Layout

The layout consisted of a elements that can be stacked vertically, or horizontally. So we needed containers that would let to stack the elements either vertically or horizontally. These can be recursive letting horziontal and vertical be stacked inside each other as well as shown in the example below.

Layout example

To achieve this we needed a Recursive JSON configuration.

Building the JSON configuration

We wanted to capture the following

  • A way to identify Horizontal/ Vertical / Element
  • Define widths of the Elements ( especially useful when horizontally stacked)
  • Identify the elements with an id so that it can be replaced with content ( more of this later in the blog )
  • Other configurations to appropriately paint the content inside an element.

So a sample JSON looked something like this.

{
  "type": "Element",
  "config": {
    "id": "e1",
    "height": "200px",
    "color": "yellow",
    "width": "12"
  },
  "children": []
}
PropertyDescription
typeOne of the values in Element, Vertical or Horizontal
configConsists of a property id and other properties to help draw the element
childrenAn array of child nodes, which follow the same format

Typically an Element will have an empty children and the others would have one or more items.

You can find a sample full blown JSON here

Working with the JSON

We used Material-UI as part of the project, and leveraged it's Grid to help with drawing our layout.

The Material UI defines Grids using <Grid \> tag. You can define a <Grid container \> that would contain many <Grid item \> which would have the content. The <Grid item \> can also take a parameter called xs which can be a number between 1- 12 as defined by it's 12 grid layout.

Translating this to our solution, we will

  • Have a Grid container for each of the Vertical items
  • No special handling for Horizontal and just let the children be created
  • Elements are rendered inside a Grid Item.

In the above case, both the Elements and Vertical are set with the width passed to it.

So we created a class called the GridContainer that takes an input config, which is nothing but a single element of the JSON, checks for it's type to be one in "Vertical", "Horizontal" or "Element" and

  • For Vertical
    • It wraps inside a <Grid item />
    • Iterates through all it's children and wraps them with a <Grid container /> each
    • Invokes the GridContainer again ( recursively ) with the child config value.
  • For Horizontal
    • Iterates through the children and invokes the GridContainer for each of it's children.
  • For Elements
    • Uses the config and draws the element.

The Key element of this class is how the config is used to build the layout in a recursive fashion.

Handling the Elements

Each of the Elements in the grid can contain a different type of element. As it was an executive dashboard, we needed a bunch of plots and their titles ( simplifying the problem for the blogs sake ).

As mentioned earlier, each of the Elements holds an id and we gave a separate mapping for each of these Ids, that consisted of

  • type which can be title or plot
  • config which is an object that consists of the values required for each of the types of elements.

This helped us to extend the number of types easily, by having a flexible config for each type of element.
The Element checks for the type and delegates it's rendering to the corresponding type ( in this case a Title or a Plot

Summary

The overall configuration looked like this that consisted of

  • Page Layout consisting of *Horizontal, Vertical and Elements that helped us draw the layout.
    • The Horizontal and Vertical components would have children and the structure can be recursive.
    • Each Element had an id
  • Viz Configuration consisting of
    • Mapping for each of the id from the Elements
    • Can be of different types, in this case Title and Plot

In the Part 2 of this blog post, we'll see how we were able to build this configuration using Drag and Drop components and persist the same into a backend.

Copyright © 2022 Arun Madhavan Govindarajan. All Rights Reserved.