SPA Frameworks
The Quick Start embed scans for [data-rocketlead-form] elements once on DOMContentLoaded. That works for static sites and CMS pages, but breaks on client-routed SPAs — the user navigates away, the container is removed, and on return the script doesn’t re-scan, leaving the new container empty.
For SPA frameworks, use the imperative window.rocketlead.forms.create() API. It returns a handle with an unmount() method you wire into your component’s lifecycle.
Loading the script
Section titled “Loading the script”Load widget.js with defer so it downloads in parallel with HTML parsing but is guaranteed to execute before your framework hydrates:
<link rel="stylesheet" href="https://cdn.rocketlead.io/widget.css"><script src="https://cdn.rocketlead.io/static/forms/widget.js" defer></script>For Next.js App Router, place this in app/layout.tsx. For Pages Router, use _document.tsx.
React / Next.js
Section titled “React / Next.js”'use client';import { useEffect, useRef } from 'react';
export function RocketLeadForm() { const ref = useRef<HTMLDivElement>(null); useEffect(() => { const handle = window.rocketlead?.forms?.create({ target: ref.current!, formId: 'your-form-id', }); return () => handle?.unmount(); }, []); return <div ref={ref} />;}The useEffect cleanup tears the form down when the component unmounts (route change, conditional rendering, etc.). Re-mounting on the next visit calls create() again.
<script setup>import { ref, onMounted, onUnmounted } from 'vue';
const el = ref(null);let handle;
onMounted(() => { handle = window.rocketlead?.forms?.create({ target: el.value, formId: 'your-form-id', });});
onUnmounted(() => handle?.unmount());</script>
<template> <div ref="el"></div></template>create() API reference
Section titled “create() API reference”window.rocketlead.forms.create({ target: HTMLElement | string, // element or CSS selector (resolved via querySelector) formId: string, prefill?: Record<string, string | string[]>, // programmatic field prefill hideFields?: string[], // field IDs / stable names to hide}): { unmount: () => void };| Field | Description |
|---|---|
target | The element (or selector) to mount the form into. Selector strings resolve to first match. |
formId | The form ID from the editor. |
prefill | Optional record of values to prefill at mount. Keys can be either field UUIDs or stable field names (name from the editor). See Prefill for the full cascade and precedence rules. |
hideFields | Optional array of field IDs or stable names to hide from the rendered form. Hidden fields are still validated — a hidden required field without a matching prefill entry will fail at submit. |
Returns { unmount } — call it from your framework’s cleanup hook to tear down the form and free resources.
Prefill + hideFields example
Section titled “Prefill + hideFields example”Inject UTM parameters captured server-side, hide them from the user, but still send them with the submission:
const params = new URLSearchParams(window.location.search);
useEffect(() => { const handle = window.rocketlead?.forms?.create({ target: ref.current, formId: 'lead-form', prefill: { utm_source: params.get('utm_source') ?? 'direct', utm_campaign: params.get('utm_campaign') ?? '', }, hideFields: ['utm_source', 'utm_campaign'], }); return () => handle?.unmount();}, []);The user sees a clean form; the submission carries the UTM context.
Idempotency
Section titled “Idempotency”create() is safe to call repeatedly with the same target — internally a WeakMap<Element, FormInstance> tracks the active mount per element, and a second create() on the same target unmounts the previous instance first. This means:
- React StrictMode (which runs effects twice in dev) doesn’t cause duplicate mounts.
- HMR re-runs are safe.
- Conditional rendering that re-mounts the same container works.
Related
Section titled “Related”- Embedding Overview — Quick Start for non-SPA setups.
- Stable Field Names —
name=""selectors that work the same way for both Quick Start and SPA mounts. - Prefill —
create()accepts aprefilloption for programmatic field population. - Troubleshooting — what to check when SPA mounts misbehave.