---
title: How to get a React website into HubSpot
description: Two manual routes (classic HubL rewrite and CMS React), the field work nobody budgets for, and how ThemeSpot turns a React site into an editable HubSpot theme with a local render and pixel loop.
---

[Skip to content](https://themespot.app/blog/react-website-into-hubspot#main-content)

[![themespot](https://themespot.app/hubfs/themespot-1.svg)](https://themespot.app/)

- Product
  
    - [Build themes/theme-development](https://themespot.app/theme-development)
    - [Manage content/content-management](https://themespot.app/content-management)
    - [Roadmap/roadmap](https://themespot.app/roadmap)
- [Pricing](https://themespot.app/pricing)

[Connect your portal](https://themespot.app/join-the-waitlist)

[← All posts](https://themespot.app/blog)

# How to get a React website into HubSpot

By [Reece Sim](https://themespot.app/blog/author/reece-sim)·October 8, 2026·1 min read

You have a React site. Maybe a designer handed you a Next.js prototype, maybe ChatGPT or Claude built the whole thing from a prompt, maybe it is your actual marketing site on Vercel. And now marketing wants it in HubSpot, where the forms, the CRM and the page editor live.

There is no "import React site" button in HubSpot, and most of the advice online is either "rewrite it in HubL" or "iframe it in and hope". Neither is "right". Here's what a seasoned HubSpot dev would do.

## First, what HubSpot actually wants

A HubSpot website is not a bundle of pages. It is a **theme**: a folder of templates, modules, fields and settings that HubSpot's page editor understands. Every heading, image and button a marketer can change in the editor has to be declared as a **field**. Every band of a page they can drag and drop has to be a **module** or a **section** inside a **drag and drop area**.

That is the real job. Not "get the pixels onto HubSpot's servers" but "turn components into editable modules without losing the design". Skip that part and you get a page nobody but a developer can touch, which is why marketing wanted HubSpot in the first place.

## Option 1: Rewrite it in HubL (the classic route)

HubL is HubSpot's templating language, a fork of Jinja. Classic themes are HTML plus HubL, and they are still the most common thing in a HubSpot portal.

 

The manual process:

1. Install the HubSpot CLI (`npm install -g @hubspot/cli`) and authenticate with a personal access key. This is what you'll use to create the skeleton, and to deploy to HubSpot.
2. Scaffold from HubSpot's CMS theme boilerplate with `hs cms theme create`.
3. Go component by component. Each React component becomes a module: a `module.html` written in HubL, a `fields.json` describing every editable prop, a `meta.json`, plus CSS and JS.
4. Translate JSX to HubL. `{props.title}` becomes `{{ module.title }}`. `.map()` becomes `{% for item in module.items %}`. Conditional rendering becomes `{% if %}`. State and effects get rewritten as vanilla JavaScript, because nothing runs on the server except HubL.
5. Rebuild the layout as templates with `dnd_area`, `dnd_section`, `dnd_column` and `dnd_module` tags, which have their own column maths and quirks.
6. Preview with `hs cms theme preview`. It runs a local proxy at hslocal.net:3000. Module previews render without the theme's styling, and template previews need a logged-in HubSpot account.
7. Upload with `hs cms upload`, set the theme active, and build a page in the editor.

This works and I have shipped dozens of sites this way. The cost is that you now own two codebases that drift apart, and the React one quietly dies.

 

> TIP: We have a Claude code plug in, that gives your agent the tools it needs to build exact replica's of any design or website, in HubL. [Find the GitHub repo here](https://github.com/reecesim/theme-devtools-for-hubspot)

 

## Option 2: CMS React (keep the React)

HubSpot has a newer route: **CMS React**, built on its developer projects framework. Modules are React components, rendered on the server and stitched into HubL templates, with optional client-side **islands** for interactivity. You get TypeScript, Vite, CSS modules, Tailwind and npm packages. This is basically the best you'll get in terms of performance.

 

The manual process:

1. Run `npx @hubspot/create-cms-theme@latest`. It scaffolds a project, installs the CLI and authenticates. Node 18 or newer.
2. You get `hsproject.json` at the root and `src/theme/my-theme/` with `components/`, `templates/`, `styles/`, `fields.json` and `theme.json`.
3. Port each React component into a module. Here is the part nobody tells you: the component still has to declare its fields. Every prop a marketer should edit becomes a typed field (text, rich text, image, link, repeater, choice), and the component reads field values instead of props.
4. Anything interactive gets wrapped as an island. Everything else renders on the server. You decide per component.
5. Templates are still HubL. Page layout, header, footer and drag and drop areas are HubL files that place your React modules.
6. `npm run start` for the local dev server (Express plus Vite, hslocal.net:3000 again). It can overlay local changes on live HubSpot pages, which is genuinely useful, but it needs an authenticated account (not recommended for building with AI)
7. `hs project upload`. The project goes through HubSpot's build health checks and auto-deploys.
8. Create a page from one of your templates in the editor.

What you lose compared with a standalone React app:

- No client-side routing. HubSpot owns the URLs and the page editor owns the pages.
- No arbitrary server data fetching. You get HubL context, GraphQL against HubSpot data, `getServerSideProps` and serverless functions.
- No editing in the design manager. It is local-only.
- Global state, context providers and your data layer mostly have to go. Each module is an island on its own.

What you keep: components, composition, TypeScript, your styling approach, and a server render that does not need a hydration blob for every band of the page.

## The part that takes all the time, either route

Nobody budgets for this, and it is where projects die: **the fields**.

 

A React component with twelve props becomes a module with twelve fields, each with a label a marketer understands, a default that is real demo content rather than "Enter heading here", help text, and a style tab so they can change surface colour and spacing without asking you. Repeaters for lists. Choice fields for variants. Image fields with alt text. Link fields that understand internal pages.

 

Then the checks HubSpot's build throws at you: reserved field names (a value field called `label` or `body` fails the build), image defaults that point at paths, a HubDB row field with no table set, a global partial whose drag and drop tree gets baked into the portal on first upload and never updates again.

 

Multiply by thirty components. That is the real migration.

## How I do it now

I built a tool because I was doing the above by hand on every client site. It is called **ThemeSpot**, and the React path runs through the hosted workspace at themespot.app.

The shape of it:

1. **Give it the site.** A folder of React, a Claude Design export, the URL of the live site, or a Figma export. It reads it as the reference design, not as code to copy.
2. **It plans the theme out loud.** Theme settings from your colours, fonts and spacing. One module per band of the page, named in the editor's words ("Testimonials", not "SocialProofGrid"). Which bits HubSpot provides natively (forms, menus, CTAs) so they are not rebuilt.
3. **It writes the React theme on a maintained headless component library.** Every heading, image, link and repeated item is an editable field with the design's content as its default. The style tab is there on every content module. The field rules above are a checker, not a wiki page, so they fail the build locally before HubSpot ever sees it.
4. **It renders locally, without a HubSpot login.** The renderer draws React modules in their real template context, fully styled, with sample content. Then a pixel loop: full-page screenshots of the design and the build at desktop and phone widths, compared, the largest difference fixed first, repeated until they match or every remaining difference is explained.
5. **It deploys on approval.** Nothing reaches your portal until a named person says so. You get the built theme, checkpoints to roll back, and a page created from a template.
6. **It keeps working after launch.** Content population, SEO and accessibility scans, and a marketer mode where the agent can edit content but never theme code.

 

The source lives in the ThemeSpot workspace while you use it. Exports are free and give you the built HubSpot theme, which uploads with HubSpot's own CLI like any other.

 

If you only want the classic route, there is a free Claude Code plugin, **Theme Dev Tools for HubSpot**, that does the design-to-HubL-theme job locally with the same renderer and pixel loop, no account needed. It ships HubL only. React themes are the hosted product.

 

```
claude plugin marketplace add reecesim/theme-devtools-for-hubspot
```

## Which route should you pick

| If you… | Pick | Why |
| --- | --- | --- |
| Are comfortable with git, React, build steps and managed deployment, and have a developer to own it | **CMS React** | You keep your components, TypeScript and tooling, and get the best performance HubSpot offers. You accept the field work and the projects build pipeline. |
| Just want it in HubSpot as soon as possible, and do not expect marketing to live in the page editor | **Classic HubL** (with the free plugin) | Fastest route to a theme in your portal. Most portable, every HubSpot developer can maintain it, and the plugin does the pixel checks locally. |
| Are less technical, or do not want to run a build and deploy pipeline yourself | **ThemeSpot** | The agent does the field work, the render and the pixel loop. You review and approve. Nothing touches the portal until you say so. |
| Want total AI content management, a portable design system, and components synced to your SaaS | **ThemeSpot** | React theme on a maintained component library, content population and QA after launch, approval gates, and a built theme you can export any time. |

 

Whatever you choose, do not iframe it. And don't embed client-side React, you'll have no search engine visibility.

 

*HubSpot is a trademark of HubSpot, Inc. ThemeSpot is not affiliated with or endorsed by HubSpot.*

![](https://themespot.app/hs-fs/hubfs/fsdf%20(1).png?width=64&height=64&name=fsdf%20(1).png)

Written by

Reece Sim

[More from this author →](https://themespot.app/blog/author/reece-sim)

[← Back to all posts](https://themespot.app/blog)

[![themespot](https://themespot.app/hubfs/themespot-1.svg)](https://themespot.app/)

Runs alongside HubSpot. Never replaces it.

Your site is yours, forever. ThemeSpot is the bonus.

All systems normal

- Legal
  
    - [Privacy](https://themespot.app/privacy)
    - [Terms](https://themespot.app/terms)

© 2026 ThemeSpot

HubSpot is a trademark of HubSpot, Inc. ThemeSpot is not affiliated with or endorsed by HubSpot.

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Reece Sim",
    "url" : "https://themespot.app/blog/author/reece-sim"
  },
  "dateModified" : "2026-10-08T02:23:24.763Z",
  "datePublished" : "2026-10-08T02:23:24.000Z",
  "headline" : "How to get a React website into HubSpot",
  "mainEntityOfPage" : {
    "@id" : "https://themespot.app/blog/react-website-into-hubspot",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://themespot.app/hubfs/themespot.svg"
    }
  }
}
```