Automated Component Generation with React

Create Components Automatically Using React

Prologue

Building a component library requires a lot of thought and time. Every component has its own requirements, and we expect it to do a particular thing. Crafting a perfectly stable, robust component is a form of art. But what if you could automate that? Not all components can be created, but at least the basic components like a Button or a text Display components can be created automatically. You might ask how? Well, I will show you so let's get started!

The Idea

React represents every component as a tree, where each child node is a react element with some props. We use the same idea to represent a component's structure as a JSON and then build an engine that goes through the JSON, creates an element for each node, and adds properties to it. We will get a component tree that can be compiled into a component.

Basic Example: Button

Every component is composed of a wrapper, a text, and an image. Consider a Button component. A basic button can be considered to be made of 2 elements:

  • button - The HTML button element
  • text - The title / child of the button. The visible text

Similarly we can visualise the UI of all components to be made of 3 elements, a wrapper, an image, and text. They can be nested, where a wrapper has a wrapper in it as a child, but ultimately you have a block of nested wrappers with either a text or an image.

Now, this is not that simple, though. A very important and possibly core part of a component is its behavior. Suppose an Accordion component, where core functionality lies in its behavior of opening and closing panels. Currently, this is not possible. But to keep things simple and to focus on creating atomic components, we will focus just on the UI.

Here is a basic example of a Button component as a JSON

Let us go over each node to understand it better.

  • The metaData stores the basic info regarding the component
  • layer can be considered as a node / element / wrapper in a component. This layer can have children which can again contain layers
  • The layer will have the properties, styles and other data related to that element / layer

More on the complete structure of the JSON below.

Architecture

A simple component can have the following properties: This button has the following properties:

  • meData - Basic information regarding the component, like its name, a unique ID, default variations, etc.
  • layer - The node of the component block (Eg. button, div)
  • properties - attributes or props of the layer ( class, tabIndex)
  • styles - css for the component block / layer
  • children - The sub-nodes / wrappers which can again contain all these properties
  • variations - The different types of a component. (Example: success button, tertiary button )

The children property can be this whole structure all over again, just like every child can be a component in React.

Steps

There are 4 main steps involved in creating this engine

  • Identifying a layer and creating an element of the layer using React.createElement
  • Adding props to it
  • Identifying children, creating elements from them based on their type, and passing them as children to the current layer
  • Extract variation properties and styles and override them

We use recursion where a node is created for every nested layer when it's of wrapper type and stop only when the layer is of type image or text.

Styles

Styles were a major concern while I was trying to make this work. I tried using inline styles, where I would inject styles with other props on each element and override them with the various styles. It worked well until I realized I could not add pseudo styles to an element, like hover, focus, etc. The solution was to create internal styles for every component and render the style element along with a component. This way I could define those states as a node in the styles object.

Example:

Every layer in the JSON has an ID. We use this ID to create a unique class name and attach styles to it.

Examples

So far, I have managed to create around 2-3 components using the engine.

Button

The JSON structure of this component is simple. But it contains variations like primary and secondary Button.

Screenshot 2022-09-18 at 11.02.26 PM.png

Input

The Input component contains three elements, the label, the actual input element, and the helper text. It has a nested structure because the label text, Input, and helper text are the children of the label element. It also has an invalid variation, as shown below, which adds a red border to the Input element.

Screenshot 2022-09-18 at 11.02.40 PM.png

For more insight and an understanding of the underlying code, please check out the GitHub repository:


Screenshot 2022-10-26 at 5.52.23 PM.png

Make sure to star it!

Limitations

While this is an interesting Idea, it can be considered just as an exploration. This is not at all scalable because creating complex components like Accordion is not at all possible for now. Some other concerns which need more thought:

  • Currently, there's no way to add behaviors to it
  • Only passing children are supported for now. It needs more implementation to enable passing more props, for example: href to a link
  • The component doesn't store any values, which limits its use cases widely

These are not just limitations. These are goals / additional steps that are needed to be implemented.

Conclusion

The Idea was not to automate the whole process. It was about creating an engine that would create components out of a JSON. But JSON can come from anywhere. If we automate the creation of the JSON, then we pretty much automate the whole process. For example, Figma files can be parsed to get layers and their styles using their API.

While it has a lot of limitations, the idea behind it is pretty interesting and out of the box. The next steps would be to make them store values and accept functions to make them interactive.