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

@0xhex/react-xray

v0.1.0

Published

Inspect React Fiber state from the browser console after an app has rendered.

Readme

react-xray

Inspect React 18 applications from the browser console after they have already rendered. No extension or pre-load integration is required.

Use react-xray only on applications you own or are explicitly authorized to inspect. React Fiber is private API, so compatibility is version-specific.

// Run on an authorized page using the supported React version:
const x = ReactXRay.xray({ verbose: true });
x.tree();

Why?

Existing tools like React DevTools require a browser extension. Libraries like bippy need to load before React. react-xray's verified read path works after React has already rendered: it discovers the existing root, finds components, reads props and hook state, and maps DOM elements back to components.

Verified 0.1.0 contract

The release check proves, against React 18.3, that:

  • ESM and CommonJS imports expose xray.
  • The browser IIFE exposes ReactXRay.xray.
  • Post-render injection discovers a root and named components.
  • DOM inspection and state reads return the expected component.
  • State dispatch, event interception, highlighting, and cleanup work against a deterministic local fixture.
  • The npm tarball works from a clean temporary consumer project.

Quick Start

The npm package is published as @0xhex/react-xray; the project and global browser API remain named react-xray and ReactXRay.

Console (one-liner)

const s=document.createElement('script');s.src='https://unpkg.com/@0xhex/[email protected]/dist/index.iife.js';s.onload=()=>{window.x=ReactXRay.xray({verbose:true});x.tree()};document.head.append(s);

CDN Script Tag

<script src="https://unpkg.com/@0xhex/[email protected]/dist/index.iife.js"></script>
<script>
  const x = ReactXRay.xray({ verbose: true });
</script>

npm

npm install @0xhex/react-xray
import { xray } from '@0xhex/react-xray';
const x = xray({ verbose: true });

Bookmarklet

See demo/bookmarklet.js — drag it to your bookmarks bar and click on any React page.

Reproducible local demo

npm ci
npm run build
python3 -m http.server 4173

Open http://localhost:4173/demo/. The page renders React first, injects the local IIFE afterward, and displays the discovered components and counter state.

API Reference

xray(options?)

Initialize react-xray. Returns an XRayInstance.

| Option | Type | Default | Description | |-----------|-------------------|--------------|------------------------------------------| | global | string \| false | '__XRAY__' | Attach instance to window[global] | | verbose | boolean | false | Log lifecycle events to console |

Finding Components

x.find('Counter')         // all components named "Counter"
x.find(/^App/)            // regex matching
x.findOne('TodoItem')     // first match or null

Returns ComponentInfo objects:

interface ComponentInfo {
  name: string;
  fiber: Fiber;
  props: Record<string, any>;
  hooks: HookInfo[];
  element: Element | null;
  key: string | null;
  children: string[];
}

Inspecting Elements

// Click an element in Elements panel, then:
x.inspectSelected()

// Or pass a DOM element directly:
x.inspect(document.querySelector('.my-component'))

Reading State

const counter = x.findOne('Counter');
x.hooks(counter.fiber)           // all hooks
x.props(counter.fiber)           // current props
x.stateAt(counter.fiber, 0)     // first useState value

HookInfo shape:

interface HookInfo {
  index: number;
  type: HookType;     // 'useState' | 'useEffect' | 'useRef' | ...
  value: any;
  dispatch?: Function; // present for useState/useReducer
}

Modifying State

const counter = x.findOne('Counter');

// Set the first useState to 42:
x.setState(counter.fiber, 0, 42);

// Experimental; may not trigger a render:
x.setProps(counter.fiber, { label: 'Modified!' });

Watching Renders

Render subscriptions require a compatible DevTools hook that React already knows about; injecting only after the initial render does not create that connection retroactively.

// Watch all renders:
const unsub = x.onRender((event) => {
  console.log(`${event.name} ${event.phase}d`);
});

// Watch specific component:
x.onRender('Counter', (event) => {
  console.log('Counter rendered!', event.phase);
});

// Stop watching:
unsub();

Intercepting Events

// Log all clicks:
x.intercept('click', (e) => {
  console.log('Click intercepted:', e.target);
});

// Block all clicks:
x.intercept('click', (e) => {
  console.log('Blocked click on', e.target);
  return false; // stops propagation
});

Component Tree

x.tree()      // print full tree
x.tree(3)     // max depth of 3

Visual Highlighting

const counter = x.findOne('Counter');
x.highlight(counter.fiber);                    // default blue
x.highlight(counter.fiber, 'rgba(255,0,0,0.3)'); // custom color
x.unhighlight();                               // remove all

Fiber Roots

x.roots()  // array of root fibers

Cleanup

x.destroy()  // remove all listeners, overlays, global reference

Recipes

1. Explore an unfamiliar React app

const x = ReactXRay.xray({ verbose: true });
x.tree();
x.find(/./).forEach(c => console.log(c.name, c.props));

2. Find and modify a counter

const c = x.findOne('Counter');
console.log('Current value:', x.stateAt(c.fiber, 0));
x.setState(c.fiber, 0, 999);

3. Monitor re-renders when a compatible hook is connected

x.onRender((e) => {
  console.log(`[${e.phase}] ${e.name}`, e.fiber.memoizedProps);
});

4. Intercept and log form submissions

x.intercept('submit', (e) => {
  const form = e.target;
  const data = new FormData(form);
  console.table(Object.fromEntries(data));
  return false; // prevent submission
});

5. Highlight all instances of a component

x.find('Button').forEach(b => x.highlight(b.fiber, 'rgba(255,165,0,0.4)'));
// Later: x.unhighlight()

6. Interactive element picker

document.addEventListener('click', function pick(e) {
  e.preventDefault();
  e.stopPropagation();
  const info = x.inspect(e.target);
  if (info) {
    console.log(info.name, info.props, info.hooks);
    x.highlight(info.fiber);
  }
  document.removeEventListener('click', pick, true);
}, true);

7. Dump all state in the app

x.find(/./).forEach(c => {
  const stateHooks = c.hooks.filter(h => h.type === 'useState');
  if (stateHooks.length > 0) {
    console.group(c.name);
    stateHooks.forEach(h => console.log(`  state[${h.index}]:`, h.value));
    console.groupEnd();
  }
});

How It Works

react-xray uses three React internals techniques:

1. DOM → Fiber Bridge

React stamps every host DOM node with a __reactFiber$<hash> property pointing to its fiber node. We discover this key once and cache it, giving us instant fiber access from any DOM element.

2. DevTools Global Hook

React looks for window.__REACT_DEVTOOLS_GLOBAL_HOOK__ on load and calls hook.inject(renderer) + hook.onCommitFiberRoot(...) on every commit. If the hook already exists (DevTools extension), we wrap it. If not, we create one and discover existing roots from the DOM.

3. Fiber Tree Traversal

React's fiber tree is a linked list: each fiber has child (first child), sibling (next peer), and return (parent). Walking this structure gives us the full component hierarchy with props, hooks state (memoizedState linked list), and DOM references.

Compatibility

| React Version | 0.1.0 status | |---------------|--------------| | 18.3 | Verified release contract | | 19.x | Unverified | | 17.x | Unverified, best effort | | 16.8+ | Unverified, best effort | | < 16.8 | Unsupported |

Limitations

  • Private API: React can change Fiber fields without a semver guarantee.
  • Production builds: Hook type detection falls back to heuristics (no _debugHookTypes). Types may be reported as unknown.
  • Render subscriptions: post-render root discovery supports reads, but onRender needs a compatible DevTools hook that React already knows about to observe future commits.
  • State mutation: setState is best effort. It prefers the DevTools renderer API and otherwise dispatches through the hook queue.
  • Props mutation: setProps depends on renderer support or direct Fiber mutation and is experimental.
  • Minified names: Production builds minify component names. Use regex patterns or inspect from DOM elements instead.
  • Server components: React Server Components don't have client-side fibers.
  • Strict mode: Double-rendering in dev mode may cause duplicate render events.

Development and release verification

npm ci
npx playwright install chromium
npm test
npm run release:check

See RELEASE.md for the exact publication and independent verification checklist. SECURITY.md documents the authorized-use boundary.

License

MIT