Writing JSX to build pixel perfect UI elements can be very time consuming and frustrating. I’m talking about the process of figuring out the exact padding, margin, flexbox, width, height etc to match the required design spec. As React engineers, our time is most well spent on what we can do uniquely - write state management logic, API calls, error handling, component architecture, animations and building complex components that require lots of user interactions.
The aim of this blog post is to provide a methodology using which designers can build the simpler UI HTML elements using Webflow and React engineers can inject complex elements / React components into the generated HTML page. This works best for sites that have less user specific / user generated content - like several b2b sites.
Note: For those who do not know about Webflow, it’s a tool that let’s designers design the UI, and it emits fully functional HTML code.
As an example, let’s consider a webpage where most of the body is generated using Webflow apart from the header and the footer - which are arbitrarily complex react components.
Creating empty divs
We start by assuming that we have already generated the HTML, JS and CSS files using webflow. The HTML file contains the head and body tags as usual.
We want to insert our React header component at the top of the body, so we add an empty <div> element with a unique id:
As we will see later, the header component will be rendered inside the div above. We will get the ref of the div using the id “webflow-header”
We then want to make place for the footer, which should go right before the closing body tag:
We also want to create a div where the whole react app will load in. Think of this as an entrypoint for the react app. From here, it will render the header and footer component into the two divs created above. We will do this using the createPortal function provided by React (as we will see later):
Adding the React bundle
Just like in a normal react app, we need to add the <script> tag that will load the bundle and run the React app:
Loading the React app
We want to load the react app in the div with the ID “react-root”. This will load the root component of your react app, which can then load the header and footer react component in their respective div tags. The react app can also be used for any other operation like analytics:
Find the header and footer div nodes from the React app
In order to inject the header and footer components into their divs, we need to first get a reference to them. We do so using the document.getElementById function in the root component of the react app
In pages where the divs have not been inserted, the value for this.headerDiv and this.footerDiv will be null. So we need to remember to do a null check before using them.
The render function
In order to inject the components, we have to call the createPortal function from inside the render function. This function takes two arguments:
We have successfully added react components to a webflow generated HTML page.
Since the injection of the components happen after the react bundle is downloaded and run, the user first sees the HTML that’s generated using Webflow, and then sees a jitter as the react components are injected (which occupy their own height and width). Unfortunately, this jitter is quite noticeable.
We can fix this by setting the body tag’s CSS to have display: none initially, and then after the components have been injected, we can set the display to block (in the componentDidMount or useEffect function). This way, the experience for the user is the same as if the whole page is made using React.
So in the componentDidMount / useEffect function, we should do the following
The above would prevent the jitter and provide a seamless experience for the user.
We saw how we can inject components into an existing HTML page generated via Webflow using the ReactDOM.createPortal function.
This method allows for quicker development of relatively static web pages saving you money. As a reference, we at SuperTokens use this method. Our home page is made completely using Webflow, excepting for the header and footer - which are injected using the method shown above.