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-dev-panel

v0.2.2

Published

A framework-agnostic, self-contained floating dev panel for React: Developer Logs, Page Performance, and a Component Graph Inspector (hover-to-source, component tree, open-in-editor).

Readme

react-dev-panel

A floating, in-app developer panel for any React project — drop in one component and get a draggable launcher with three tools:

  • 🐛 Developer Logs — live console + network capture (status, duration, GraphQL op name/type, request/response bodies & headers), with source/level filters, search, "this page" scoping, and expandable entries.
  • 📊 Page Performance — Core Web Vitals (LCP, INP, CLS, FCP, TTFB) with ratings and fix hints.
  • 🧩 Component Graph Inspector — hover any element to identify its component, lock it, browse the parent → renders → imports tree, see what's mounted on the current page, and open the source file in your editor.

Built on MUI (peer dependency) so it inherits your app's theme. Gating is a prop you control — nothing renders in production unless you say so.


Table of contents


Requirements

react-dev-panel renders inside your app's existing MUI ThemeProvider, so these are peer dependencies you already have in an MUI app:

| Peer | Version | | --- | --- | | react / react-dom | >=18 | | @mui/material | >=7 | | @emotion/react, @emotion/styled | >=11 | | react-icons | >=5 | | typescript (optional) | >=5 — only the graph-generator CLI uses it |

Not using MUI? This package won't render correctly without an MUI theme in context. (A style-agnostic build is out of scope for now.)

Install

npm i -D react-dev-panel
# or: pnpm add -D react-dev-panel   /   yarn add -D react-dev-panel

Quick start

Mount <DevPanel/> once, near your app root, inside your MUI ThemeProvider. It renders nothing in production by default.

import { DevPanel } from 'react-dev-panel';

export function Providers({ children }) {
  return (
    <ThemeProvider theme={theme}>
      {children}
      <DevPanel enabled={process.env.NODE_ENV !== 'production'} />
    </ThemeProvider>
  );
}

A draggable wrench launcher appears in a corner. Open it → Developer Logs and Page Performance work immediately with zero further setup.

The Component Graph Inspector needs a generated graph + a way to open files — see its setup section. Until then, its hover/lock still identifies components by name (from the React fiber tree); file paths and relationships light up once the graph is served.

Configuration

<DevPanel/> takes a flat config object:

| Prop | Type | Default | Purpose | | --- | --- | --- | --- | | enabled | boolean | process.env.NODE_ENV !== 'production' | Master gate. You own the access decision (env, internal-user role, flag). | | getRoute | () => string \| undefined | location.pathname | Current route, for the "this page" / route displays. Wire your router (see per-framework notes). | | openInEditor | (loc, editor?) => void \| Promise<void \| boolean> | protocol URL + copy | How source files open. Use serverOpenInEditor with an adapter for the best result. | | graphEndpoint | string | — | URL serving the component-graph JSON. Use DEFAULT_GRAPH_ENDPOINT with an adapter. | | editor | 'auto' \| 'vscode' \| 'cursor' \| 'webstorm' \| 'zed' | 'auto' | Preferred editor. auto lets the server detect the editor running the project. | | theme | { accent?: string; accentContrast?: string } | — | Minor accent overrides (most styling comes from your MUI theme). | | tools | string[] | all | Restrict/reorder tools by id: 'logs', 'perf', 'graph'. |

Example, fully wired (Next.js):

'use client';
import { usePathname } from 'next/navigation';
import { DevPanel, serverOpenInEditor, DEFAULT_GRAPH_ENDPOINT } from 'react-dev-panel';

export function DevPanelMount() {
  const pathname = usePathname();
  return (
    <DevPanel
      enabled={process.env.NODE_ENV !== 'production'}
      getRoute={() => pathname ?? undefined}
      graphEndpoint={DEFAULT_GRAPH_ENDPOINT}
      openInEditor={serverOpenInEditor}
      tools={['graph', 'logs', 'perf']}
    />
  );
}

Tools

| Tool | id | Setup | Notes | | --- | --- | --- | --- | | Developer Logs | logs | none | Patches console + fetch/XHR on first mount. Persists to sessionStorage (per tab). | | Page Performance | perf | none | Uses web-vitals. INP needs an interaction before it reports. | | Component Graph Inspector | graph | graph + endpoint | See below. Degrades gracefully without them. |

Component Graph Inspector setup

Three steps: generate the graph, serve it, wire the client.

1. Generate the graph

A CLI scans your source with the TypeScript compiler and writes a JSON graph (components, files, lines, and renders / imports / route edges):

npx dev-panel-graph --scan src
# → .dev-panel/component-graph.json

Re-run it after adding/moving components. Common options:

npx dev-panel-graph --scan src,packages/ui/src --out .dev-panel/graph.json --root .

Add it to your scripts so it's easy to refresh:

// package.json
"scripts": {
  "gen:dev-panel": "dev-panel-graph --scan src"
}

Gitignore the output:

.dev-panel/

2. Serve it (pick an adapter)

The graph JSON lives outside public/, so a tiny dev endpoint serves it (and opens files). Pick the adapter for your stack — all three mount the same two endpoints (/dev-panel/graph, /dev-panel/open-file).

Vite — one line; also regenerates the graph on dev start:

// vite.config.ts
import { devPanel } from 'react-dev-panel/vite';

export default defineConfig({
  plugins: [react(), devPanel({ scan: ['src'] })],
});

Next.js (App Router) — add two route files (gate them yourself; dev/internal only):

// app/dev-panel/graph/route.ts
import { createGraphRoute } from 'react-dev-panel/next';
export const dynamic = 'force-dynamic';
export const { GET } = createGraphRoute({
  enabled: () => process.env.NODE_ENV !== 'production',
});
// app/dev-panel/open-file/route.ts
import { createOpenFileRoute } from 'react-dev-panel/next';
export const dynamic = 'force-dynamic';
export const { POST } = createOpenFileRoute({
  enabled: () => process.env.NODE_ENV !== 'production',
});

In a monorepo where cwd differs from the repo root, pass root / graphFile: createGraphRoute({ root: path.resolve(process.cwd(), '../..'), graphFile: 'apps/web/.dev-panel/component-graph.json' }).

Any Node server (CRA proxy / Express / custom) — connect-style middleware:

import { createDevPanelMiddleware } from 'react-dev-panel/server';
app.use(createDevPanelMiddleware());

3. Wire the client

Point <DevPanel/> at the served endpoint and the server-backed opener:

import { DevPanel, serverOpenInEditor, DEFAULT_GRAPH_ENDPOINT } from 'react-dev-panel';

<DevPanel enabled={isDev} graphEndpoint={DEFAULT_GRAPH_ENDPOINT} openInEditor={serverOpenInEditor} />

That's it — open the panel, enable Inspect mode, hover, click to lock, and use the Graph, Page, and File tabs.

No adapter / fully client-only? Omit graphEndpoint. Hover still names components and the Page scan still lists them; file paths/relationships require the served graph, and open-in-editor falls back to editor:// protocol URLs (then copy).

Open-in-editor

The detail card has a primary Open in editor button plus a force: row (VS Code / Cursor / WebStorm). Resolution order:

  1. Server (openInEditor={serverOpenInEditor} + an adapter) → posts to /dev-panel/open-file, which runs launch-editor and opens the editor running the project (respects $EDITOR). Most reliable. The force: buttons map to code / cursor / webstorm CLIs — those must be on your PATH.
  2. Protocol (default opener, no server) → vscode:// / cursor:// / webstorm:// / zed://.
  3. Copy the path to the clipboard if both fail.

⌘/Ctrl + click on a hovered element opens it directly.

Gating & security

  • enabled is the master switch and defaults to non-production. In production it renders nothing unless you explicitly pass enabled truthy — gate that on an internal-user role/flag.
  • The adapter endpoints accept an enabled() callback — gate them too (NODE_ENV and/or auth); they 404 in production by default.
  • Open-file requests are confined to the repo root (path-traversal guarded).
  • The graph JSON is read from disk by the endpoint and is not placed under public/, so it's never a statically served production asset. Keep .dev-panel/ gitignored.
  • Sensitive request headers (authorization, cookie, …) are redacted before logging, and presigned URL signatures are collapsed.

Custom tools

Register your own tool before mounting <DevPanel/>:

import { registerTool } from 'react-dev-panel';
import { LuFlask } from 'react-icons/lu';

registerTool({
  id: 'my-tool',
  title: 'My Tool',
  subtitle: 'Does a useful thing',
  color: 'primary', // primary | info | warning | success | error
  icon: <LuFlask size={19} />,
  Panel: ({ onClose }) => <YourMuiPanel onClose={onClose} />,
  // optional:
  Overlay: MyAlwaysMountedOverlay,          // self-gating layer
  useBadge: () => ({ label: '3', tone: 'error' }), // menu-row badge
  init: () => { /* one-time setup on mount */ },
});

Restrict/reorder which tools show with the tools prop.

Theming

The panel uses your app's MUI theme — colors, radius, typography all follow it automatically.

  • Tweak the launcher accent via theme={{ accent: '#6950E8' }}.
  • The detail chips use MUI's soft Chip variant. If your theme registers soft (e.g. the Minimals template) it renders tinted; otherwise it falls back to a plain chip. No action needed.

CLI reference

dev-panel-graph [--root <dir>] [--scan <dir,dir>] [--out <file>]

  --root   repo root (default: cwd) — file paths in the graph are relative to this
  --scan   comma-separated dirs to scan (default: src)
  --out    output JSON path (default: .dev-panel/component-graph.json)

The Vite adapter runs this for you on dev-server start (generateOnStart, default true).

API reference

react-dev-panel

  • DevPanel(config) — the mountable component.
  • registerTool(def), getRegisteredTools() — custom tools.
  • serverOpenInEditor, createServerOpenInEditor(endpoint?) — client opener that POSTs to the open-file endpoint.
  • defaultOpenInEditor — protocol-URL + copy opener (used when none is provided).
  • useDevPanelConfig() — read the resolved config inside a custom tool.
  • DEFAULT_GRAPH_ENDPOINT, DEFAULT_OPEN_ENDPOINT'/dev-panel/graph', '/dev-panel/open-file'.
  • Types: DevPanelConfig, DevPanelTheme, ToolDefinition, ToolPanelProps, EditorType, SourceLocation, OpenInEditor, ComponentGraph, ComponentGraphNode, ComponentGraphEdge.

react-dev-panel/nextcreateGraphRoute(opts), createOpenFileRoute(opts) (+ the endpoint constants and serverOpenInEditor). react-dev-panel/vitedevPanel(opts) (default + named export). react-dev-panel/servercreateDevPanelMiddleware(opts).

Troubleshooting

| Symptom | Fix | | --- | --- | | Launcher doesn't appear | Check enabled is truthy; ensure it's mounted inside your MUI ThemeProvider. | | Panels look unstyled / wrong colors | It must render inside an MUI ThemeProvider. | | Graph tab says "not generated" | Run npx dev-panel-graph, then click Retry graph load (or reload). Confirm the adapter is mounted and graphEndpoint matches. | | Hover shows MuiButtonBaseRoot / a host tag | You hovered a low-level/MUI element. Hover a container, or use Graph → search / the Page tab to find your app components. The resolver climbs to the nearest component that's in the graph. | | "Open in editor" copies instead of opening | With an adapter: ensure the editor CLI (code/cursor/webstorm) is on PATH, or set $EDITOR before starting dev. Without an adapter, it relies on the OS protocol handler. | | Page tab empty after navigation | Click Rescan — heavy/async pages mount content after the auto-scan. |

License

MIT