By Chester Liu

Imagine designing a marketing website visually—editing copy, rearranging components—and instantly exporting clean, ready-to-deploy React code. At Relume, we’re making that possible.

Relume is an AI-powered site builder that helps people go from a prompt to a fully editable website in minutes. Our latest feature takes this one step further: users can now export their designs as React code that reflects all their customizations—no manual tweaks required.

In this post, we’ll walk through one of the hardest technical challenges we faced while building this feature: making sure that user edits in our design tool are accurately reflected in the exported code—and how we solved it using a structured JSX annotation system.

The Challenge: Reflecting User Edits in React Code

After generating a page with AI, users often tweak things—editing text, removing buttons, changing layout elements. We needed a way to take these edited designs and generate clean React code that mirrors every change.

We already had a React component library powering the designs, but it wasn’t designed for export. We couldn’t easily take a modified version of a component and turn it back into source code without breaking structure or losing edits.

And we knew this system couldn’t just solve today’s problem. It had to scale. As we introduce styling controls, custom logic, and other user-driven changes in the future, our export system needs to stay flexible and reliable.

Original Component

Screenshot 2025-02-17 at 2.54.30 PM.png

Screenshot 2025-02-17 at 2.54.18 PM.png

Component after edits

Screenshot 2025-02-17 at 2.56.01 PM.png

Screenshot 2025-02-17 at 2.56.19 PM.png

Note how the paragraph and the other button is removed, and all copies are now changed. These modifications showcase just the beginning of what our system needs to handle as we continue to expand editing capabilities with advanced styling and complex component controls.

Our Solution: Turn React Component into Template

We first explored manipulating the source code directly using string operations—but that quickly became fragile and hard to scale. Simple changes worked, but anything beyond that broke easily. And parsing arbitrary JSX reliably is no small task.