How to Steal Any React Component

出处:https://fant.io/react/

原文: 阅读原文 译文: 中文
双语 译文

I'll show you how to steal any component on a production React website's components without source code or access to the repo - just the website running in our browser. For example, here is Cursor web's agent sidebar.

Normally, you'd need the source code. But here's the thing - React actually leaves a lot of breadcrumbs in the browser. More than you might think. And if we're clever about collecting these breadcrumbs and feeding them to an LLM, we can reconstruct the original components.

So that's what we're going to do. By the end, we'll have a working React component written by the help from an LLM. Let's start from the very basics.

Here's something you need to understand first. When you're looking at a React app in the browser, there are actually two trees living in memory.

Let's use this website as an example.

The DOM is the browser's representation of the page and consists of HTML elements: divs, buttons, spans, etc. You can see it in the Elements tab of your dev tools. This is what the browser renders on screen.

React Fiber is React's internal tree. It's a parallel structure that React maintains, and it knows things the DOM doesn't know, such as:

  • Which React component created which DOM elements
  • What props were passed to each component
  • The component's state, hooks, everything

And here's the beautiful thing - we can access this from the browser. React attaches Fiber nodes directly to DOM elements. Since React 16, any React app exposes this and it's what React Developer Tools uses under the hood.

So we can walk the DOM, and for each element, we can ask: "Hey, which React component made you? And what props did it get?"

This is our entry point and how we're going to see inside the React app.

Next, let's think about what we need to reconstruct a component.

Imagine there's a Button component on the page. It's used in three places:

  • A primary button in the header
  • A disabled button in some form
  • A secondary button in the footer

Same component, different props, different HTML output.

What we're going to do is collect all of these instances. For each one, we record:

  1. The props it received
  2. The HTML it produced

Now, here's how we know these are all the same component. In React Fiber, every fiber node has a type property. And for component instances, this type points to the actual function or class. It's the same reference in memory.

Every Button on the page, no matter what props it has, will have the exact same type. We can use this to bucket them together.

Alright, now we have everything we need to prompt an LLM. For each component type, we have:

  1. Multiple examples of props → HTML mappings
  2. The minified source code (we can get this via type.toString())

The minified code isn't super readable for us humans, but LLMs understand minified code remarkably well and get hints about what the original component did. And the examples show the input-output relationship concretely.

So we're essentially saying:

"Here's a React component. I'm going to show you several examples of props and the HTML output. Please write clean React code that replicates this component."

The LLM generates a component. Great! But how do we know if it's correct? This is the critical part to make this work.

We take the LLM's generated component and we render it ourselves. We pass in the same props from our examples, and we capture the HTML output.

Then we compare: does our HTML match the original website's HTML?

If it doesn't match - we show the LLM the diff saying

"Hey, when I pass these props, you produced this HTML, but the original site produced this other HTML. Please fix your code."

We loop until it passes, or we give up after a few retries.

This is like a little test suite that we automatically derived from the production site.

Now here's a detail that matters a lot.

Some components contain other components. A LoginForm might render a Button inside of it. A Card might render an Avatar.

When we're reconstructing LoginForm, we need to already have a working Button. Otherwise how would we correctly build our LoginForm?

So we process components in dependency order. Start with the leaf components - the ones at the bottom of the tree that don't contain any other custom components. Then work our way up to the parents.

This is just a topological sort on the component dependency graph.

This works a lot of the time, but below are some situations where it doesn't.

Problem: JavaScript animations

Imagine a progress bar: <Progress value={90} />. If we snapshot it mid-animation, the DOM might say width: 67% while the props say value={90}.

Our LLM writes a component that correctly produces width: 90% for value={90}, however that doesn't match our snapshot!

We're comparing against a single frame in time, but the real component was animating.

Problem: Interactive state

A dropdown that's currently open. A modal that's visible. The HTML depends on internal state we can't observe from the props alone.

The fallback

When verification fails repeatedly, we just snapshot the HTML as-is. It's not a real component anymore, just frozen HTML. But at least we can keep making progress on other components.

Once we've reconstructed the component and all of its dependencies, we compose them into a complete component. We also copy over:

  • CSS
  • Assets (images, fonts, etc)

And then we have it: a fully working React project that looks like on the original website, built from reconstructed components.

To recap:

  1. We exploited React Fiber to see inside the component tree
  2. We collected props → HTML examples for each component type
  3. We asked an LLM to write code that fits those examples
  4. We verified correctness by rendering and comparing
  5. We processed components bottom-up, leaves first

The key insight is that React gives us all this structure for free. The DOM alone is just a soup of divs. But React Fiber tells us: "These three buttons are the same component. This one got these props, that one got those props."

That structure makes reverse engineering possible.

Is it perfect? No. Animations break it, complex state breaks it, and sometimes the LLM just can't figure out the pattern. But for static-ish UI components - buttons, cards, layouts, forms - it works surprisingly well.

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.148.4. UTC+08:00, 2026-01-25 09:20
浙ICP备14020137号-1 $访客地图$