React DevTools Inline
react-devtools-inline provides a mechanism to embed the full React Developer Tools interface directly within a browser-based application, such as online code editors (e.g., CodeSandbox, StackBlitz) or debugging tools (e.g., Replay). Unlike the standalone `react-devtools` package, this package is specifically designed for integration into host environments. The current stable version is 7.0.1, though it is part of the larger React monorepo which sees frequent updates, particularly for React v19 and related tooling like `eslint-plugin-react-hooks`. A critical differentiator is its reliance on several *experimental* React APIs, necessitating the use of `react@experimental` and `react-dom@experimental` in the target application, making it unsuitable for applications running stable React releases. It exposes distinct frontend and backend APIs for setup within a main window and an iframe, respectively.
Common errors
-
Error: A React root is required to render. You provided an element.
cause Attempting to render the DevTools component returned by `initializeFrontend` using `ReactDOM.render` instead of `ReactDOMClient.createRoot`.fixUse `ReactDOMClient.createRoot(containerElement).render(<DevToolsComponent />)` for the DevTools frontend component. -
React DevTools: Could not find the React global hook. Is React loaded?
cause The `initialize` function from `react-devtools-inline/backend` was called *after* React had already loaded in the target iframe, preventing DevTools from injecting its hook.fixEnsure the script that calls `initialize(iframe.contentWindow)` is executed as the very first script within the iframe, before any React-related imports or scripts. -
SyntaxError: Cannot use import statement outside a module
cause Using `require()` or attempting to run ESM `import` statements in a CommonJS-only Node.js environment or without proper bundler configuration.fixEnsure your project is configured for ES Modules (e.g., `"type": "module"` in `package.json` for Node.js, or use a bundler like Webpack/Rollup/Vite that handles ESM correctly for browser environments).
Warnings
- breaking This package relies on several *experimental* React APIs. You must install `react@experimental` and `react-dom@experimental` in your project for it to function correctly. It is not compatible with stable React releases.
- gotcha The backend `initialize(windowOrGlobal)` function *must* be called before React (or any package that imports React) is loaded within the target `window` or `iframe`. Calling it after React has loaded will prevent DevTools from hooking into React's internals.
- gotcha The `initialize` function from `react-devtools-inline/frontend` returns a React component that must be rendered using `ReactDOMClient.createRoot` (from `react-dom/client`) instead of the older `ReactDOM.render`. This is due to its use of React's concurrent features.
- gotcha The backend `activate(windowOrGlobal)` function should only be called once the frontend DevTools interface has been fully initialized. Calling it prematurely can lead to missed tree-initialization events and an incomplete DevTools display.
Install
-
npm install react-devtools-inline -
yarn add react-devtools-inline -
pnpm add react-devtools-inline
Imports
- initialize (backend)
const { initialize } = require('react-devtools-inline/backend');import { initialize } from 'react-devtools-inline/backend'; - activate (backend)
const { activate } = require('react-devtools-inline/backend');import { activate } from 'react-devtools-inline/backend'; - initialize (frontend)
const { initialize } = require('react-devtools-inline/frontend');import { initialize } from 'react-devtools-inline/frontend'; - hookNamesModuleLoaderFunction
const hookNamesModuleLoaderFunction = () => import('react-devtools-inline/hookNames');
Quickstart
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ReactDOMClient from 'react-dom/client';
import { activate, initialize as initializeBackend } from 'react-devtools-inline/backend';
import { initialize as initializeFrontend } from 'react-devtools-inline/frontend';
// Create a minimal React app to run inside the iframe
const IframeApp = () => {
const [count, setCount] = React.useState(0);
return (
<div>
<h1>Hello from Iframe React App!</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
};
const setupDevTools = () => {
const iframe = document.createElement('iframe');
iframe.id = 'react-app-iframe';
iframe.style.width = '50%';
iframe.style.height = '100%';
iframe.sandbox = 'allow-scripts allow-same-origin';
document.body.appendChild(iframe);
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write('<div id="iframe-root"></div>');
iframeDoc.close();
const DevTools = initializeFrontend(iframe.contentWindow);
// Render the DevTools component in the main window
const devToolsRoot = ReactDOMClient.createRoot(document.getElementById('devtools-root'));
devToolsRoot.render(
<React.StrictMode>
<DevTools
hookNamesModuleLoaderFunction={() => import('react-devtools-inline/hookNames')}
/>
</React.StrictMode>
);
// Backend setup in the iframe
// Important: initializeBackend must be called before React loads in the iframe
initializeBackend(iframe.contentWindow);
// Simulate React loading in the iframe after backend is initialized
// In a real scenario, the iframe content would load React itself
const iframeReactRoot = ReactDOMClient.createRoot(iframeDoc.getElementById('iframe-root'));
iframeReactRoot.render(
<React.StrictMode>
<IframeApp />
</React.StrictMode>
);
// Activate backend once frontend is ready and React is loaded in iframe
activate(iframe.contentWindow);
};
// Initial HTML structure
const mainRoot = document.getElementById('root');
if (mainRoot) {
mainRoot.innerHTML = '<div id="devtools-root" style="width:50%; height: 500px; float: left;"></div>';
setupDevTools();
}