Micro Frontends — Integrate React with other applications and frameworks.

Allow a react application to be part of a micro frontends architecture

Originally posted on my personal blog debuggr.io

This is a followup article for this tweet

This may address only specific use cases, like already existing applications or mini applications that you can’t or won’t rewrite, or stand-alone application which you need to provide to others to implement on their websites and you want to provide an API to interact with your application.

In this article / tutorial we will build a very basic react “widget” (a Counter!) and a very basic react application. we will see what problems we face when we try to interact with the two applications and how ReactDOM.render API help us to pass data in and out the applications while keeping the great unidirectional flow.

Note: you can implement this with any view framework / library,
I just chose to do it with 2 react applications because i mostly work with react, but you can pass and get data from a react app with angular / vue / jQuery or vanilla JS. it doesn’t matter.

Lets Code

To make it easy to start and not waste time on building the “widget” and main application, i published a repository that will save you the time and hassle.

This repo holds 2 folders:
1. main-app (the main application project)
2. counter-app (our counter widget project)

Both of them built using create-react-app (because it’s easy, it’s fast and it’s just works)

Note that you don’t have to do it with create-react-app, you may already have a js build system running on your existing application.
You may want to read
Add React to a Website from the DOCS


clone the repository to your local drive

git clone https://github.com/sag1v/react-external-integration-starter.git

Install And Run


cd main-app
npm install
npm start


cd counter-app
npm install
npm start

You may have prompted with this message

a message of “Something is already running on port 3000”

Just confirm with “y” and press enter.

If both applications are running fine, you should see something similar to this

main-app page

main app starter page

counter-app page

counter app starter page

In our main-app there’s nothing special going on right now, but lets look at the counter-app



const el = document.getElementById('counter-app');
ReactDOM.render(<Counter />, el);

As you can see, there’s nothing fancy here. just a counter with 2 buttons.
The only thing we want to focus on is our props.
We want to be able to pass props from the outside, props likeinitialCount,onCountUpdate and title. This is easy when we are inside the context of the Counter react app, but we want to be able to do that outside of that, from a different application.

But before we solve our problem, lets see what is our problem. lets render the Counter inside our main-app.

To do that, we will need to run a build of our counter and include the bundled files of the counter-app in the index.html file of our main-app.

In your command line, make sure you are at the /counter-app folder and run

npm run build

This will generate the js and CSS files for production.
Note: for simplicity and ease, i tweaked the build process of the counter-app.
Every time we run build, the generated files will be placed in:


This will make it easier for us to see the changes to the code as we go, so we don’t need to manually copy and paste the files there.

If all went well you should see these files in your main-app folder:


Now go to


Make sure you include the CSS and JS files of the counter , we also need to render a div with the counter-app id

<div id="counter-app"></div>

Your index.html should end up with something like this:

And this is how our page should look like

So now we have both our main-app and Counter on the same page, but this is not what wanted. we want the Counter inside the main-app.
We could render the counter-app div inside our App component instead of just throwing it in the index.html file, but this won’t work.

In fact, lets see why it won’t work
Remove this from index.html

<div id="counter-app"></div>

And move it to App.js (main-app/src/App.js)

After you hit save, you can see the Counter is no longer displayed on our screen. In fact we have an invariant 200 error in console with a link to https://reactjs.org/docs/error-decoder.html/?invariant=200

Target container is not a DOM element.

In other words, our counter-app div container is not there.

But wait, didn’t we just render it inside our App.js?
This message is coming from our Counter application, from these lines:

const el = document.getElementById('counter-app');
ReactDOM.render(<Counter />, el);

What happens here is that our Counter application is running before our main-app application. So App.js didn’t run yet and we didn’t pass a valid second argument to ReactDOM.render.

Our First Real Challenge

So this is the first challenge we need to solve, we want to control the order of the scripts or moreover the order of the function calls.
Of course this is one of the oldest challenges we have in JavaScript and the solution to that is modules, bundlers etc.
Our script tag is at the end of the body block but the problem here is that webpack is injecting the main-app scripts in run-time to the end of the body block as well. This is why we can’t run Counter after the main-app scripts.
We could hack around with the async / defer attributes of the script tag but that won’t solve our problem, even if it did solve the ordering, it won’t solve our real problem: get data in and out of the Counter and control it.

First Part Of The Solution

Maybe, instead of just running this code

const el = document.getElementById('counter-app');
ReactDOM.render(<Counter />, el);

We will wrap it inside a function, and expose it globally. this way, other applications can decide when to run it and will do it explicitly.

Before we dive in to the actual implementation, we also want to enable an un-mount of our widget. ReactDOM has another method just for that unmountComponentAtNode

So we need a reference to the counter-app container for both methods.
lets modify our index.js of count-app to this:

As you can see, we expose a global object ReactCounter with 2 methods:
1. mount
2. unmount

Both will use ReactDOM under the hood.

Now lets build counter-app with our command (make sure you are in /counter-app folder)

npm run build

If we refresh the page of main-app we won’t see the counter but we also won’t get an error, as we never tried to render to a none existing element. that’s good.

Now we can call our mount function inside App.js.
Lets do that after the first render of App.js with the componentDidMount life cycle method, this way we are sure the counter-app div is already rendered.

After you hit save you can see our counter below the react logo, INSIDE our App.js! 👊

We know we can un-mount it as well, so just for fun lets toggle it with a click on the react logo.
Lets make these changes in our App.js

As you can see, we added a state with a showCounter key.
we replaced componentDidMount with componentDidUpdate so we can react to changes of the satet, and we conditionally call ReactCounter.mount or ReactCounter.unmount based on showCounter .
We also added a toggleCounter handler and attached it to the onClick prop of the logo’s <img/> element.

You should end up with this

Passing props

While this is nice, we also want to pass data to our Counter . if we look at our mount function, there’s nothing stopping us to pass it parameters and it will pass parameters to the <Counter/> component.
In counter-app/src/index.js you should change your code to this:

After you build counter-app with npm run build you can go to main-app/src/App.js and pass an object props to mount.
I passed {title: ‘Whaaa! cool’}

And this is how it looks like:

It’s like the render you know and love!

Now lets revisit a quote from my tweet above:

You can call ReactDOM.render multiple times. Not only that but it actually won’t re-mount the entire application, instead it will trigger a diffing…

Now we know it won’t re-mount the entire application, that’s what ReactDOM.render and ReactDOM.unmountComponentAtNode are for. but what do we mean by “trigger a diffing”?

Well it’s like the render method of our class components in this case. when the life cyclerender method is invoked, it will trigger the Reconciliation process. ReactDOM.render will do the same.

Lets put it to test, we can store the title value in the state of our App.js , change it with an input and see if our Counter can get the updated values.

In our App.js we will change to this code:

And this is how it should look like:

Get data back

Well, we also wanted to get data back from our widget, if you remember we can pass onCountUpdate callback to get the current count . So if we can pass props as an object, nothing is stopping us from passing functions inside that object.

Lets add a div in our App.js that will show the current count.
We will need to pass a handler to the Counter and store the current count in App.js ‘s state as well.

Lets change App.js to this:

Note that we also pass the initialCount prop with a value of 3 to the Counter.
And this is the result:

We did it! we are communicating with an “isolated” react application, we pass data to it and able to get data back from it. but we are not done yet! we may have solved our general challenge but if we think about it, we still have 2 major issues. we can’t create multiple instances and our code is imperative as hell. Let’s make it more “react’ish”.

The multiple instances challenge

Looking at our Counter’s API in index.js :

We can see that we have a problem, the Counter forces us to use the same id for its container. If we think about it, this is not the Counter’s responsibility to decide what kind of container to render itself, and maybe it should not even do the job of querying the DOM to get the container. maybe the Counter should just get a reference to the element? Lets try it.

In counter-app/src/index.js change to this code:
don’t forget to run npm run build after the change.

In main-app/src/App.js change to this code:
note how we omit the "counter-app”id attribute from our div’s

You should see a similar result to this:

What we did here is that we passed a reference to the actual element to the mount and unmount methods. we could instead pass a selector like .myClass or #myId and use document.querySelector, but i think passing the element itself is respecting the separation of concerns in a better way.
Yay, we now have multiple instances support! 💪

The imperative code challenge

One of the core concepts and methodology of react is a Declarative way to write UI’s. we do it with Components.
If we look at our code in App.js we see a mess, its an imperative hell (i remind you that this is only a simple Counter and not a real world app!).
What if we wrap this entire code in a reusable component, lets say we call it… <ReactCounter /> so its easy to distinguish it from the real Counter.js.

Lets see how such component would look like:
You can create the new file main-app/src/ReactCounter.js

Look how clean and concise it is.
note that we are using a React.PureComponent here, you may need a regular React.Component.

Lets look on how App.js is using this new component:
Don’t forget to import ReactCounter from ‘./ReactCounter’

Now this looks much better, we can’t even tell that ReactCounter is an external stand-alone application. it looks and behave like any other component.

Of course the page should look the same as before, we just improved our code.

Wrapping up

We observed on how we can interact with a separate and isolated react application, i chose to use another react application to interact with it but this is not limited only to react. you can call our mount function and pass it the props object with any framework you work with, these are just JavaScript functions.
As i mentioned at the top, this may solve a specific problem. This is not the “normal” way we write our applications, but it’s good to know we can do that when we need it, thanks to the flexible and solid API of react and ReactDOM.

Thank you for your patience, I hope it helped you in some way.
If you have any comments / suggestions or questions, please feel free to comment.

I would love to see some examples of this approach with other frameworks, take the bundled files of the counter-app and interact with other frameworks / libraries.


It’s highly recommended to read Integrating with Other View Libraries from the react DOCS.

You can read more of my articles at my blog debuggr.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store