React Grab Documentation

repository·main·Indexed 25 days ago

https://github.com/aidenybai/react-grab

A tool for developers to copy UI elements along with their underlying source code context, including component stacks and file locations, to improve the accuracy and speed of AI agents. It includes a CLI for installation and configuration, support for frameworks like Next.js, Vite, TanStack Start, and Webpack, and a performance benchmarking suite for analyzing DOM density and V8 CPU profiles.

Tokens
15.8K
Snippets
29
Records
102
Agent score
93%

What's inside React Grab

  1. Understand @react-grab/openstory story types

    main

    The playground uses two distinct types of stories to inspect the ReactGrabRenderer overlay UI:

    1. Component stories: These render UI elements (toolbar, selection label, context menu, comments dropdown, etc.) using mocked props. They are used to inspect specific UI states like idle, context menu, comment input, and pending dismiss without side effects.
    2. Playground stories: These import react-grab for its side effects, causing init() to run against the story DOM. These are used for testing hover and grab interactions against realistic scenarios such as:
      • Composite Dashboard: Dense-DOM selection testing (sidebar, metric cards, charts, data tables).
      • Freeze Demo: Verifying freeze-animations and freeze-updates using a bouncing animated timer.
      • Live Updates: Verifying freeze-updates against continuously re-rendering components.
  2. Understand the source resolution pipeline

    main

    React Grab uses a multi-layer pipeline to transform a DOM element into a specific file path, line number, and component name. The process follows these stages:

    1. DOM to React Fiber: Uses getStack() to find the nearest ancestor with an associated React fiber (skipping text nodes or elements outside React).
    2. Fiber to Owner Stack: Constructs the component hierarchy using bippy.
      • React 19+: Uses the _debugStack property.
      • React 17-18: Invokes component functions/constructors in a guarded environment to generate a stack trace and identify the component frame.
    3. Source Map Symbolication: Resolves bundled URLs to original source files by fetching and decoding source maps via @jridgewell/sourcemap-codec.
    4. Server Component Enrichment: For React Server Components (RSC), it performs two passes:
      • Pass 1: Maps function names to virtual rsc:// URLs.
      • Pass 2: POSTs frames to the Next.js dev server's /__nextjs_original-stack-frames endpoint to resolve virtual URLs to real file paths.
    5. Normalization & Filtering: Cleans file names (stripping origins, internal schemes, and HMR query params) and filters out framework-internal components (e.g., Next.js App Router wrappers, React Suspense, or library-prefixed components like motion. or styled.).
  3. Understand react-grab design principles

    main

    react-grab is designed to inspect live React applications by freezing the UI and providing an overlay. Key principles include:

    • UI Freezing: Pauses rendering, CSS animations, transitions, SVG animations, Web Animations API (WAAPI), and GSAP timelines to prevent visual shifts during inspection.
    • Isolation: The overlay UI is mounted in a Shadow DOM to prevent style leakage. The host element uses pointer-events: none to avoid intercepting clicks intended for the underlying page.
    • Non-intrusive Event Handling: When a keyboard shortcut is claimed, it patches KeyboardEvent.prototype.key to return an empty string to the host application, avoiding unreliable stopPropagation calls with React's synthetic event system.
    • Plugin-based Architecture: All user actions (copying snippets, HTML, styles, adding comments, etc.) are implemented as plugins. This allows developers to modify the copy pipeline via onBeforeCopy, transformSnippet, and transformCopyContent without forking the library.
    • Lazy Loading: The rendering layer (SolidJS components) is loaded via dynamic import() to ensure the interaction logic initializes immediately.
  4. Analyze V8 CPU profiles and deopt traces

    main

    To debug performance hotspots or V8 deoptimizations:

    1. Generate a profile: Use nr test:perf:trace or nr test:perf:full.
    2. Analyze: Use nr perf:analyze -- perf/<label> to get a combined report of scenario metrics, CPU hotspots, and deopt sites.
    3. Visual Inspection: Load the generated .cpuprofile in the Chrome DevTools "Performance" panel for a full flame chart.

    Requirement: Pair with pnpm build:profiling (or pnpm --filter react-grab build:profiling from the repo root) to ensure symbols are unminified.

  5. Run performance benchmarks with nr test

    main

    Performance benchmarks (@perf scenarios) run under the Playwright project and capture browser-native signals including INP, Long Tasks, Long Animation Frames, FPS, Memory (JS heap, DOM nodes, etc.), Chromium process CPU, CSS activity, and Workload shape.

    Note: All commands must be run from the packages/react-grab/ directory.

  6. Manually install React Grab in Next.js (Pages router)

    main

    For Next.js projects using the Pages router, add the React Grab script into your pages/_document.tsx. It is recommended to only load this in development mode.

    import { Html, Head, Main, NextScript } from "next/document";
    
    export default function Document() {
      return (
        <Html lang="en">
          <Head>
            {process.env.NODE_ENV === "development" && (
              <Script
                src="//unpkg.com/react-grab/dist/index.global.js"
                crossOrigin="anonymous"
                strategy="beforeInteractive"
              />
            )}
          </Head>
          <body>
            <Main />
            <NextScript />
          </body>
        </Html>
      );
    }
  7. Develop with @react-grab/openstory

    main

    To develop the @react-grab/openstory playground, you must first build the core CSS. After that, you can start the development server.

    1. Build core CSS: pnpm --filter react-grab prebuild
    2. Start openstory: pnpm --filter @react-grab/openstory dev

    The playground will be available at http://localhost:6006.

    # Build the core CSS once (required before first run)
    pnpm --filter react-grab prebuild
    
    # Start openstory
    pnpm --filter @react-grab/openstory dev
  8. Understand the react-grab interaction lifecycle

    main

    The interaction state is managed as a GrabState discriminated union. The lifecycle transitions through several modes based on user input:

    Activation Modes

    • Hold-to-activate: User holds a key for a configurable duration (idle -> holding -> active).
    • Toggle-activation: User toggles the tool on/off (idle -> active).

    Active States

    Once active, the tool moves through these phases:

    • hovering: Tracks pointer and highlights elements under it.
    • frozen: Triggered when a user clicks an element to lock the selection.
    • dragging: Triggered when the user draws a rectangle to select multiple elements.
    • justDragged: A brief transitional phase after a drag ends.

    Copying Flow

    • copying: Generating clipboard content.
    • justCopied: Showing success feedback.

    Branching Logic:

    • If activated via hold, the tool returns to active after a copy so the user can continue inspecting.
    • If activated via toggle, the tool deactivates after a copy.
  9. Enable hardware GPU counters on macOS

    main

    On macOS, hardware GPU counters require a privileged system sampler. You must pre-authorize the sampler using sudo -v before running the benchmark with the PERF_GPU=1 flag.

    To ensure accurate results, use PERF_HEADED=1 to keep graphics hardware enabled and PERF_BROWSER_CHANNEL=chrome to use the installed Chrome build. Keep the browser window in the foreground; the harness will fail if the window is hidden or loses focus.

    sudo -v
    PERF_HEADED=1 PERF_BROWSER_CHANNEL=chrome PERF_GPU=1 PERF_LABEL=feature pnpm test:perf
  10. How to use React Grab for element selection

    main

    React Grab converts browser selections into source context for AI agents.

    1. Hover over any UI element in your application.
    2. Press ⌘C (macOS) or Ctrl+C (Windows/Linux).
    3. Paste the copied context into your agent.

    The copied context includes the selected element and its component stack with source locations, for example: [<a class="ml-auto inline-block text-sm" href="#">Forgot your password?</a> in LoginForm (at components/login-form.tsx:46:19)]

  11. Check for new grabs without blocking

    main

    If you are performing a long-running task and want to check if the user has provided a new instruction (a new grab) without pausing your current work, use the pull command with --wait 0.

    If the command returns empty output, no new grabs have been made. If it prints a JSON object, the user has redirected you; you should stop your current task and act on the new grab immediately.

    npx react-grab@latest pull --max-age 0 --wait 0