Free prompt · An island, not a rewrite

Add interactivity without surrendering the page.

Ask an agent to “make this module interactive” and the easy answer is to turn the whole thing into client-side JavaScript. CMS-React gives you a sharper tool: islands — the page renders server-side first, and only the marked subtree hydrates. This prompt makes your agent propose the smallest island — boundary, props, hydration timing — before it writes any code.

Free · no signupWorks with any agentProposal before code
The prompt

Copy it, run it on a real module

Take one module that needs a single interactive element — a toggle, tabs, a live filter. The prompt opens by surveying how your theme handles interactivity today, asks what you're adding, and won't write code until you've approved the boundary.

Islands build prompt — paste into your agent
I want to add one interactive element to a HubSpot CMS-React module without
turning the module into client-side JavaScript. On this platform, modules
render on the server and ship no JS by default; only a component imported
with the ?island suffix and rendered through the Island component hydrates on
the client and may use hooks, state, or event handlers. Keeping the island
small is a blast-radius decision, not just a performance one — that's the
constraint you build inside.

PHASE 0 — Orient, then ask. Read the theme and tell me which modules exist,
which already use islands, and how interactivity is currently handled. Then
ask me:
  - Which module am I changing, and what single piece needs to be
    interactive (a counter, tabs, a filter, a form with live validation)?
  - What should it feel like — instant on load, or fine to hydrate lazily?
  - Is this module used on one page or many? (If I don't know, list what
    you'd check.)
Then STOP and wait for my answers.

PHASE 1 — Propose the smallest island. Before writing any code, show me:
  - THE BOUNDARY — exactly which subtree becomes the island, and what stays
    a server-rendered component. If your boundary wraps more than the
    interactive piece, shrink it and explain why the smaller cut works.
  - THE PROPS — the exact serializable props the island needs. No functions
    across the boundary — and only the values required, never a whole data
    blob: island props are serialized into the page HTML and visible in page
    source.
  - THE HYDRATION TIMING — whether this island should hydrate on load, when
    the browser is idle, or only when scrolled into view, and why.
  - WHAT DOESN'T CROSS — anything (handlers, secrets, big objects) that must
    stay on the server side of the seam.
Wait for my go-ahead on the proposal.

PHASE 2 — Build it. Write the island component and the module changes,
including the import with its ?island suffix and the ts-ignore line above it
that the untyped island import needs. Keep everything outside the island
exactly as it was — same server rendering, same fields, same markup.

PHASE 3 — Prove the containment. Show me how to verify that the page still
renders server-side first, that only the island's JavaScript loads, and that
nothing outside the boundary changed. If any check can only be done in the
account or a live preview, say so explicitly — list it as mine to run, and
tell me exactly what to look for.

Start with Phase 0 now.
Why it works

Small islands are a blast-radius decision

01

The boundary comes first

The agent must name the island's exact subtree — and defend why nothing smaller works — before writing a line. That single constraint kills the default failure: wrapping the whole module in client-side JavaScript to make one button clickable.

02

The seam stays clean

Island props must be serializable — no functions — and they're visible in the page source, so the prompt forces a data-only diet across the boundary. The seam the platform enforces becomes a seam the agent designs deliberately.

03

Containment gets proved

The build ends with verification, honestly split: what the agent can show from the code, and what only you can check in a live preview — that the page still renders server-first and only the island hydrates.

What you get back

The proposal you approve before code exists

The shape of a Phase 1 proposal — the boundary drawn and defended, the props on a data-only diet, the hydration timing chosen for the page, and the verification split between what the agent proves and what you check live.

Example result · the shape to expect
For "make the pricing table's billing toggle interactive," Phase 1 comes back:

THE BOUNDARY
  island:  <BillingToggle />          — the switch + the two price labels
  server:  everything else            — table, tiers, CTAs, footnotes
  (rejected: wrapping the whole PricingTable — 40 lines interactive,
   400 shipped to the client for no reason)

THE PROPS  — serializable only, visible in page source
  monthlyPrice: 24        annualPrice: 240        currency: "USD"
  (NOT the whole pricing object — the island needs three values)

HYDRATION  "visible" — below the fold on both pages that mount this module

DOESN'T CROSS  the analytics handler (stays server-config), tier metadata

VERIFY  agent: island compiles, module markup unchanged outside the seam
        you:   view page source — prices render server-side; toggle JS
               loads only when scrolled into view
The mechanics

How islands actually work in CMS-React

The prompt's constraints aren't style preferences — each one traces to how the platform renders. The specifics, sourced:

In HubSpot· How islands work in CMS-Reactdocs ↗

The page is fully rendered server-side first (HTML, no interactivity); the island's JS is then loaded and hydrated on the client. Only islands can use hooks, state, or event handlers — a plain server component that calls useState will error.

To make one: import Island from @hubspot/cms-components, import your component with a ?island suffix on the path, and render <Island module={Component} … />. Props must be serializable — no functions — and they're serialized into the page HTML (visible in page source), so pass only what the island needs. hydrateOn tunes when it hydrates: "load" (default), "idle", or "visible". The ?island import is untyped, so it needs a ts-ignore line above it.

Reflects HubSpot as of June 2026 · verify against the linked docs

Keep going · HubSpot CMS

One island is a build. The seams are a practice.

Islands are one seam in a platform full of them — code vs. live content, one page vs. every page, local vs. the account. The HubSpot CMS module teaches the full set, so you can direct an agent through a real theme without clobbering the work of everyone who edits it live.

Prefer it as a reusable tool? This prompt is the public twin of the kit's /build skill. The full kit ships with the course.

More free prompts

Keep building your kit