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

show-component

v2.3.0

Published

Quickly navigate to the line of code that is responsible for rendering a component

Readme

show-component

Inspired by react-show-in-atom and click-to-component.

Development tool for React apps. Right-click any element to jump straight to the component source code in your editor.

Works by reading React fiber internals and resolving source maps in the browser — no server or build plugin required.

Background

Tools like click-to-component, react-dev-inspector, and locatorjs let you click any React element in the browser to jump to its source in your editor. They all relied on _debugSource — a property that React attached to fiber nodes when the codebase was compiled with @babel/plugin-transform-react-jsx-source.

React 19 removed _debugSource, breaking the entire ecosystem of click-to-source tools (facebook/react#32574). The removal was intentional — the Babel transform had limitations: it only worked with JSX, didn't compose with source maps, and was DEV-only.

show-component takes a different approach. Instead of relying on a build-time Babel transform, it reads _debugStack — the Error stack trace that React 19 attaches to every fiber node at render time — and resolves original source locations through your bundler's standard source maps at runtime.

This means:

  • No build plugin required — works with any bundler that emits source maps (Vite, webpack, esbuild, etc.)
  • No Babel JSX transform — no @babel/plugin-transform-react-jsx-source or similar needed
  • React 19 compatible — uses the same mechanism React itself now uses for component stacks

This library does not fall back to _debugSource and exclusively relies on _debugStack. If you are on React 18 or earlier, you are better served by click-to-component or react-dev-inspector, which are designed around the Babel JSX source transform.

Installation

npm install show-component

Setup

Render <ShowComponent /> once at the root of your app (usually next to your router or providers). It does not wrap children — it attaches a global context-menu listener.

import { ShowComponent } from 'show-component';

function App() {
  return (
    <>
      <ShowComponent />
      <YourApp />
    </>
  );
}

Usage

| Shortcut | Action | |---|---| | Alt + Right Click | Navigate directly to the source of the clicked component | | Alt + Shift + Right Click | Show a popover with the full component chain; click any entry to navigate, or inspect its props |

Navigation opens the file in your editor via a custom protocol URL (default cursor://file/…). Use the editorScheme prop to target a different editor.

Source Root

By default, resolved paths are URL-relative (e.g. /src/components/Foo.tsx). To get absolute paths your editor can open directly, set the project root:

// Via prop
<ShowComponent sourceRoot="/Users/me/project" />

// Via global
window.__SHOW_COMPONENT_SOURCE_ROOT__ = '/Users/me/project';

// Programmatic
import { configureSourceRoot } from 'show-component';
configureSourceRoot('/Users/me/project');

Editor Scheme

By default, navigation uses the cursor:// protocol. To open files in a different editor, pass the editorScheme prop with the appropriate URL scheme:

// VS Code
<ShowComponent editorScheme="vscode" />

// VS Code Insiders
<ShowComponent editorScheme="vscode-insiders" />

// Windsurf
<ShowComponent editorScheme="windsurf" />

The scheme is the part before :// in the generated URL (e.g. vscode://file/path/to/File.tsx:12:5).

Custom Navigation

Override the default editor-opening behavior with onNavigate:

<ShowComponent
  onNavigate={({ source, line, column, url, componentName }) => {
    console.log(`${componentName} → ${source}:${line}:${column}`);
  }}
/>

When onNavigate is provided, the protocol handler is not triggered — the consumer decides what to do with the resolved location.

Custom Click Target

By default, Alt + Right Click navigates to the component closest to the clicked DOM element (index 0 in the chain). Use getClickTarget to choose a different component:

<ShowComponent
  getClickTarget={(chain) => {
    // Skip design-system primitives, navigate to the first "real" component
    const skip = new Set(['Button', 'Icon', 'Text', 'Box']);
    const idx = chain.findIndex((c) => !skip.has(c.componentName));
    return idx >= 0 ? idx : undefined; // undefined = default (index 0)
  }}
/>

Each entry in the chain is a ComponentHandle with the component name and props available immediately. Source-map resolution is lazy — it only happens if you call resolveSource():

<ShowComponent
  getClickTarget={async (chain) => {
    // Prefer deciding by name alone (zero overhead)
    const byName = chain.findIndex((c) => c.componentName === 'PageContent');
    if (byName >= 0) return byName;

    // Fall back to resolving source locations when names aren't enough
    for (const handle of chain) {
      const loc = await handle.resolveSource();
      if (loc && !loc.source.includes('node_modules')) return handle.index;
    }
    return undefined;
  }}
/>

The callback can return synchronously (just a number) or asynchronously (a Promise). Returning null or undefined falls back to the default behaviour.

API

<ShowComponent />

| Prop | Type | Default | Description | |---|---|---|---| | sourceRoot | string | — | Absolute path to the project root. Converts URL-relative paths to absolute filesystem paths. | | editorScheme | string | "cursor" | URL scheme for editor navigation (e.g. "vscode", "vscode-insiders", "windsurf"). See Editor Scheme. | | onNavigate | (event: NavigationEvent) => void | — | Custom navigation handler. Replaces the default protocol call. | | getClickTarget | (chain: ComponentHandle[]) => number \| null \| undefined \| Promise<…> | — | Customise which component Alt+Right-Click navigates to. See Custom Click Target. |

configureSourceRoot(root: string | undefined)

Sets the source root programmatically. Equivalent to the sourceRoot prop.

NavigationEvent

interface NavigationEvent {
  source: string;       // Resolved source file path
  line: number;         // Line number in the original source
  column: number;       // Column number in the original source
  url: string;          // The editor protocol URL (e.g. cursor://file/…)
  componentName?: string;
}

ComponentHandle

Passed to getClickTarget. Immediate data is available synchronously; source resolution is lazy.

interface ComponentHandle {
  componentName: string;                    // Display name of the component
  props: Record<string, unknown> | undefined; // Component props (from fiber)
  index: number;                            // Position in the chain (0 = closest to DOM)
  resolveSource: () => Promise<{            // Lazy source-map resolution (cached)
    source: string;
    line: number;
    column: number;
  } | null>;
}

Requirements

  • React 16.8+ (uses fiber internals available in development builds)
  • Development mode only — fiber debug info (_debugOwner, _debugStack) is stripped in production builds

License

MIT