# Create a React Micro Frontend
# Prerequisites
- A working instance of Entando
- Verify dependencies with the Entando CLI:
ent check-env base-develop
# Create a React App in an Entando Bundle
# Create the Bundle Project
Initialize a new bundle project with the default files and folders:
ent bundle init simple-bundleFrom the root bundle folder, add an MFE to the bundle project:
cd simple-bundle ent bundle mfe add simple-mfe
# Create a React App with Vite
Vite (opens new window) generates a React app in seconds, and can build it into the single file a micro frontend needs.
Create a React app in
simple-bundle/microfrontends/. Use the same name you gave the MFE, so the app fills the emptysimple-mfefolder:npm create vite@latest microfrontends/simple-mfe -- --template reactInstall the dependencies:
cd microfrontends/simple-mfe npm installIn
package.json, add astartscript.ent bundle runstarts a React micro frontend withnpm install && npm start, and the Vite template only definesdev, so without it the command fails withMissing script: "start":"scripts": { "start": "vite", "dev": "vite", "build": "vite build", "lint": "oxlint", "preview": "vite preview" }Alternative
To leave
package.jsonas Vite generated it, override the command in thesimple-mfeentry ofentando.jsoninstead. Acommands.runvalue takes precedence over the default:"commands": { "run": "npm install && npm run dev" }In the bundle's
entando.json, addbuildFolderto thesimple-mfeentry:"buildFolder": "dist"WARNING
Unless told otherwise, the Entando CLI looks for the build output in
build/, the folder Create React App used. Vite writes todist/, so without this settingent bundle packfails: the Vite build succeeds, but the bundle image can't findmicrofrontends/simple-mfe/buildand the CLI reports onlyDocker build failed with exit code 1.From the root bundle folder, start the app:
ent bundle run simple-mfeThe React app opens in your browser at
http://localhost:5173.
# Configure the Custom Element
The steps below wrap the app component with an HTML custom element. The connectedCallback method renders the React app when the custom element is added to the DOM, and disconnectedCallback cleans it up when the element is removed.
In
simple-mfe/src, create a directory namedcustom-elementsIn
custom-elements, createWidgetElement.jsxwith this code:import { createRoot } from 'react-dom/client'; import App from '../App'; class WidgetElement extends HTMLElement { connectedCallback() { this.mountPoint = document.createElement('div'); this.appendChild(this.mountPoint); this.root = createRoot(this.mountPoint); this.root.render(<App />); } disconnectedCallback() { this.root?.unmount(); } } customElements.define('simple-mfe', WidgetElement);Use `.jsx` for files that contain JSX
Vite compiles JSX only in
.jsxand.tsxfiles. Create React App also accepted JSX in.jsfiles; Vite does not, and the build fails.Custom Element Names
- Must contain a hyphen
-in the name (opens new window) - Cannot be a single word
- Should follow
kebab-casenaming convention
- Must contain a hyphen
# Replace the Template App
The demo page in the Vite template is not suited to a micro frontend. Its stylesheet styles body, h1, p and other elements globally, so it would restyle the whole Entando page around your widget, and it loads icons from absolute paths such as /icons.svg, which don't exist once Entando serves the widget.
Replace the contents of
src/App.jsx:import { useState } from 'react'; import './App.css'; function App() { const [count, setCount] = useState(0); return ( <div className="simple-mfe"> <h2>Hello from a React micro frontend</h2> <button type="button" onClick={() => setCount(count => count + 1)}> Count is {count} </button> </div> ); } export default App;Replace the contents of
src/App.css. Every rule is scoped under the widget's own class, so nothing leaks onto the page:.simple-mfe { padding: 16px; font-family: system-ui, sans-serif; } .simple-mfe button { padding: 6px 12px; cursor: pointer; }
# Display the Custom Element
Replace the entire contents of
src/main.jsxwith this single line:import './custom-elements/WidgetElement';src/index.cssis deliberately no longer imported: its rules are global and would apply to the whole page.In
index.html— at the root ofsimple-mfe, not inpublic/— replace<div id="root"></div>with:<simple-mfe></simple-mfe>Custom elements always need an explicit closing tag in HTML:
<simple-mfe />is read as an opening tag.Observe your browser automatically redisplay the React app.
Congratulations!
You’re now using a custom element to display a React app.
# Build a Single File for Entando
By default Vite builds a complete web application, with an index.html and content-hashed file names. Library mode produces one JavaScript file and one stylesheet with fixed names instead, which is what Entando loads for a micro frontend.
Replace the contents of
vite.config.js:import react from '@vitejs/plugin-react' import { defineConfig } from 'vite' export default defineConfig({ plugins: [react()], define: { 'process.env.NODE_ENV': JSON.stringify('production'), }, build: { lib: { entry: 'src/main.jsx', name: 'simple-mfe', formats: ['umd'], fileName: () => 'simple-mfe.js', cssFileName: 'simple-mfe', }, }, })Keep the `define`
In library mode Vite does not replace
process.env.NODE_ENV, and React reads it. Without this line the bundle referencesprocess, which doesn't exist in the browser, and the widget fails withprocess is not defined. It also makes the bundle use React's production build, roughly a third of the size.Build the micro frontend:
npm run builddist/now containssimple-mfe.jsandsimple-mfe.css.
# Optional: Serve Static Assets
Images and other files imported from src/ — for example import logo from './logo.svg' — need no extra work: library mode inlines them into the bundle.
Files in public/ are copied to dist/ as they are. Don't reference them with an absolute path such as /logo.svg, because in Entando that resolves against the site root rather than your widget. Build the URL from the base path Entando publishes for the widget instead:
const basePath = window.entando?.widgets?.['simple-mfe']?.basePath ?? '';
const logoUrl = `${basePath.replace(/\/$/, '')}/logo.svg`;
For an EPC the base path is published under a different key; see Create an Entando Platform Capability.
# Display the React MFE in Entando
# View the Widget
Place the React micro frontend onto a page to see it in action.
In the
Entando App Builder, go toPages→ManagementChoose an existing page (or create a new one) and select
Designfrom its ActionsFind your widget in the
Widgetssidebar and drag it onto the pageClick
PublishClick on
View Published Page
Congratulations!
You now have a React micro frontend running in Entando!
Next Steps
- Add a Configuration MFE in App Builder
- Create an Entando Platform Capability with your React bundle
← Introduction Angular →