npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-inspect-overlay

v0.1.5

Published

A Vue-DevTools-style component inspector for React — hover the page to highlight components, click to jump to their source. Works with both legacy ReactDOM.render and React 18/19 createRoot.

Readme

react-inspect-overlay

A Vue-DevTools-style component inspector for React. Drop one component into your app, click the floating button, then hover the page — every React component highlights with its box model, name and size. Click one to jump straight to its source in your editor.

  • 🔍 Inspect only — no panels, no component tree, just the thing you reach for most: "which component is this, and where does it live?"
  • 📦 Box-model overlay — margin / border / padding / content layers, just like Chrome and Vue DevTools.
  • ⌨️ Keyboard navigation — walk the component tree with / , freeze the highlight with Space, all without leaving inspect mode.
  • ⚛️ Animated launcher — a draggable React-atom button that orbits while idle and accelerates when inspect mode is armed.
  • 🎯 Click to open in editor — jumps to the exact JSX line and auto-detects your running editor (VS Code, Cursor, WebStorm, Sublime …). Works with Vite and Create React App / CRACO, on the web and inside Electron.
  • 🧩 Works with both React architectures — legacy ReactDOM.render roots and modern createRoot / hydrateRoot (React 16.8 → 19).
  • 🛡️ Shadow-DOM isolated — the UI lives in its own shadow root, so the host app's CSS can never touch it and vice versa.
  • 🪶 Zero CSS dependency — fully self-contained inline styles.

Install

npm install -D react-inspect-overlay
# or
pnpm add -D react-inspect-overlay
# or
yarn add -D react-inspect-overlay

How it works (the mental model)

The inspector is made of two independent pieces. Understanding them makes every setup below obvious:

  1. The runtime overlay — <Inspector />. A normal React component you mount once. It draws the highlight, reads React's fiber data to find component names, and on click resolves the picked component's source location (file:line:column).

  2. The source location. The browser doesn't know which file a <div> came from — that information only exists at build time. So a build-time plugin stamps every JSX element with a data-source-loc="file:line:col" attribute. At pick time the overlay reads it back and asks the dev server to open that file in your editor.

So "open in editor" needs two things wired up: a build plugin (to stamp the location) and a dev-server endpoint (to actually launch the editor). Which plugin/endpoint you use depends on your bundler — that's the only thing that changes between the setups below.

JSX  ──build plugin──►  <div data-source-loc="src/App.tsx:12:5">
                                      │  (click)
                          <Inspector> reads the attribute
                                      │  fetch()
                          dev server ──launch-editor──►  VS Code opens App.tsx:12

Mount <Inspector /> the same way everywhere:

import { Inspector } from "react-inspect-overlay";

createRoot(document.getElementById("root")!).render(
  <>
    <App />
    <Inspector />
  </>,
);

<Inspector /> disables itself when NODE_ENV === "production", so it is safe to leave mounted, and it marks its own fibers as internal so it never inspects itself. Everything below is just "how do I wire the build plugin for my bundler".


Setup by environment

A) Vite (web app)

Add the Vite plugin — it does both jobs (stamps JSX through its Babel pass and serves the open-in-editor endpoint):

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { reactInspector } from "react-inspect-overlay/vite";

export default defineConfig({
  plugins: [reactInspector(), react()],
});

Plugin order. Keep reactInspector() before your React plugin. @vitejs/plugin-react-swc (and other JSX compilers) erase JSX before any later plugin can read it, so they must run after reactInspector(). With @vitejs/plugin-react (the Babel variant) the order is corrected automatically — the inspector injects through its Babel pass — but a wrong order with the SWC variant is reported on startup so it never fails silently.

What happens: the plugin tags JSX during dev, and registers GET /__react-inspector/open on Vite's dev server. The overlay fetches that URL on click, and launch-editor opens the file. Done.

Using a CommonJS vite.config.js (project without "type": "module")? It still works — the package ships a CommonJS build, so require() resolves without renaming the file to .mjs:

// vite.config.js  (CommonJS)
const { reactInspector } = require("react-inspect-overlay/vite");
module.exports = { plugins: [reactInspector(), require("@vitejs/plugin-react")()] };

B) Create React App / CRACO (web app)

CRA has no Vite plugin pipeline, so wire the two pieces through CRACO:

  • Stamp JSX with the standalone Babel plugin (react-inspect-overlay/babel).
  • Serve the open-in-editor endpoint with the bundled dev-server middleware (react-inspect-overlay/middleware).
// craco.config.js  (CommonJS — no need to rename to .mjs)
const isDev = process.env.NODE_ENV === "development";
const { reactInspectorBabel } = require("react-inspect-overlay/babel");
const { reactInspectorMiddleware } = require("react-inspect-overlay/middleware");

module.exports = {
  babel: {
    plugins: isDev ? [reactInspectorBabel] : [],
  },
  devServer: (config) => {
    if (isDev) {
      const prev = config.onBeforeSetupMiddleware;
      config.onBeforeSetupMiddleware = (server) => {
        server.app.use(reactInspectorMiddleware());
        if (typeof prev === "function") prev(server); // keep CRA's middlewares
      };
    }
    return config;
  },
};

What happens: CRACO injects the Babel plugin into CRA's babel-loader, so your JSX gets data-source-loc tags; the middleware answers GET /__react-inspector/open and launches your editor with launch-editor — resolved from inside this package, so you never add it as a direct dependency (this matters under pnpm, which doesn't hoist transitive deps). The isDev guard and the Babel plugin's own production no-op keep all of this out of shipped builds.

The overlay also falls back to CRA's built-in GET /__open-stack-frame-in-editor, but whether that route is mounted varies across CRA / CRACO versions — the bundled middleware makes "open in editor" deterministic.

C) Electron + Vite (electron-vite / vite-plugin-electron)

Identical to (A) — there is nothing Electron-specific to do.

// vite.config.ts  (renderer config)
import { reactInspector } from "react-inspect-overlay/vite";
import react from "@vitejs/plugin-react";

export default { plugins: [reactInspector(), react()] };

Why it just works: in dev, Electron loads the renderer from the Vite dev server (win.loadURL("http://localhost:5173")). So the page's origin is the dev server — the overlay's fetch("/__react-inspector/open") reaches Vite directly. No IPC, no main-process code, no extra config.

D) Electron + CRA / CRACO

Identical to (B) — use the exact same craco.config.js (Babel plugin + middleware), and load the renderer from the CRA dev server in development:

// main process (dev): load the renderer from the CRA dev server
win.loadURL("http://localhost:31001");

Why it just works: the renderer's origin is the CRA dev server, so the overlay's request to /__react-inspector/open lands on the middleware you mounted in craco.config.js. The editor launches from the dev server's Node process — your machine — exactly where you want it. No IPC bridge required.

If you ever load the renderer from a file:// build instead of the dev server, there is no dev server to ask — <Inspector /> still highlights and logs to the console, it just can't open files. That's expected; inspecting is a dev-time activity.


Setup at a glance

| Environment | Build plugin | Opens editor via | | ---------------------- | ----------------------------- | ----------------------------------- | | Vite (web) | react-inspect-overlay/vite | built into the Vite plugin | | CRA / CRACO (web) | react-inspect-overlay/babel | react-inspect-overlay/middleware | | Electron + Vite | react-inspect-overlay/vite | Vite plugin (renderer = dev server) | | Electron + CRA / CRACO | react-inspect-overlay/babel | react-inspect-overlay/middleware |

Without any build plugin the inspector still works — it shows component names and logs the picked element to the console; it just can't open files.

ESM & CommonJS. The package ships both builds, with import and require export conditions for every entry (., /vite, /babel, /middleware). A CommonJS craco.config.js or vite.config.js can require() it without switching the file to .mjs.

How to use it

  1. Click the floating React-atom button (or press Alt+Shift+C).
  2. Move the cursor over the page — components highlight with their box model.
  3. While inspecting:
    • click a component to open its source,
    • ↑ / ↓ walk to the parent / child component,
    • Space freeze the highlight (so you can read the label),
    • Esc or right-click to cancel.
  4. Drag the button to reposition it against any edge.

API

<Inspector />

| Prop | Type | Default | Description | | --------- | ---------------------------- | -------------- | ----------------------------------------------------------------- | | onPick | (pick: PickResult) => void | open-in-editor | Override what happens when a component is picked. | | accent | string | "#61dafb" | Accent colour for the launcher and highlight. | | enabled | boolean | auto | Force on/off. Auto = enabled unless NODE_ENV is "production". |

PickResult is { element, componentName, tagName, source }.

reactInspector(options?)react-inspect-overlay/vite

The Vite plugin (build tagging and the dev-server endpoint in one).

| Option | Type | Default | Description | | -------- | -------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | editor | string | auto-detect | Editor to open files in. Omit to auto-detect the running editor (VS Code, Cursor, WebStorm, Sublime, Vim …); set to force one, e.g. "code". |

reactInspectorBabelreact-inspect-overlay/babel

The standalone Babel plugin for non-Vite bundlers (CRA / CRACO, webpack, …). Add it to your Babel plugins. No-ops when NODE_ENV === "production".

reactInspectorMiddleware(options?)react-inspect-overlay/middleware

A connect/express-compatible dev-server middleware that serves the open-in-editor endpoint (GET /__react-inspector/open) for non-Vite setups. Mount it in development only.

| Option | Type | Default | Description | | -------- | -------- | ----------- | ------------------------------------------------------------------------------ | | editor | string | auto-detect | Editor to open files in. Omit to auto-detect; set to force one, e.g. "code". |

Why two architectures?

React exposes its fiber bookkeeping on host DOM nodes under a key whose prefix changed between major versions — __reactInternalInstance$… (React 16, legacy ReactDOM.render) and __reactFiber$… (React 17–19, legacy roots and createRoot). The inspector reads both, so it resolves components no matter how the host app mounts.

Contact

Author: Qobiljon Jumaboyev

For questions, suggestions or security concerns, reach out through the channels above.

License

MIT © Qobiljon Jumaboyev