I am trying to make a theme for hubspot and I need a formField to use different forms in the same template but I can’t get hubspot to renderize any form!!
import React, { useState, useEffect, useRef } from ‘react’
import {
ModuleFields,
TextField,
ImageField,
BooleanField,
RepeatedFieldGroup,
LinkField,
FormField
} from ‘@hubspot/cms-components/fields’
import ‘../../../styles/output.css’
import logo from ‘../../../assets/supertekLogo.png’
/* ----------- COMPONENT ----------- */
export function Component({ fieldValues = {} }) {
const {
title,
description,
links = \[],
backgroundImage,
useBackground,
form\_field\_name
} = fieldValues
const [isMenuOpen, setIsMenuOpen] = useState(false)
const [formLoading, setFormLoading] = useState(true)
const formRef = useRef(null)
const backgroundStyle = useBackground && backgroundImage?.src
? {
backgroundImage: \`url(${backgroundImage.src})\`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
}
: {}
useEffect(() => {
if (!formRef.current) return
setFormLoading(true)
// Clear the form container first
formRef.current.innerHTML = ''
// Check if we have form data
if (!form\_field\_name) {
console.log('No form field data available')
formRef.current.innerHTML = '\<p class="text-white text-center">Please configure a form in the module settings.\</p>'
setFormLoading(false)
return
}
// Log the form data for debugging
console.log('Form field data:', form\_field\_name)
// Handle different possible form data structures
let embedCode = null
if (form\_field\_name.embed\_code) {
embedCode = form\_field\_name.embed\_code
} else if (form\_field\_name.form\_id) {
// If we have a form ID but no embed code, we might need to construct it
embedCode = \`\<script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/embed/v2.js">\</script>
<script>
hbspt.forms.create({
region: "na1",
portalId: "YOUR\_PORTAL\_ID", // You'll need to replace this with your actual portal ID
formId: "${form\_field\_name.form\_id}"
});
</script>`
} else if (typeof form\_field\_name === 'string') {
embedCode = form\_field\_name
}
if (embedCode) {
try {
const wrapper = document.createElement('div')
wrapper.innerHTML = embedCode
formRef.current.innerHTML = ''
while (wrapper.firstChild) {
formRef.current.appendChild(wrapper.firstChild)
}
// If the embed code contains a script tag, we need to execute it
const scripts = formRef.current.querySelectorAll('script')
scripts.forEach(script => {
const newScript = document.createElement('script')
if (script.src) {
newScript.src = script.src
} else {
newScript.textContent = script.textContent
}
document.head.appendChild(newScript)
})
console.log('Form rendered successfully')
setFormLoading(false)
} catch (error) {
console.error('Error rendering form:', error)
formRef.current.innerHTML = '\<p class="text-white text-center">Form could not be loaded. Please check the form configuration.\</p>'
setFormLoading(false)
}
} else {
console.log('No embed code found in form data')
formRef.current.innerHTML = '\<p class="text-white text-center">Please configure a form in the module settings.\</p>'
setFormLoading(false)
}
}, [form_field_name])
return (
\<div className="relative w-full min-h-screen text-white dark-bg" style={backgroundStyle}>
{/\* Header \*/}
\<header className="flex justify-between items-center px-6 py-4 max-w-[1440px] mx-auto">
\<img src={logo} alt="Logo" className="max-w-[150px]" />
{/\* Desktop nav \*/}
\<nav className="hidden md:flex gap-8">
{links.map((link, idx) => (
\<a
key={idx}
href={link.url?.href \|\| '#'}
target={link.url?.open\_in\_new\_tab ? '\_blank' : '\_self'}
rel={link.url?.no\_follow ? 'nofollow' : undefined}
className="text-white text-sm no-underline hover:text-\[#A3FF12] transition"
>
{link.text}
\</a>
))}
\</nav>
{/\* Mobile burger \*/}
\<button
onClick={() => setIsMenuOpen(!isMenuOpen)}
className="md:hidden flex flex-col justify-center items-center w-8 h-8 space-y-1 z-50"
aria-label="Toggle menu"
>
\<span className="block w-6 h-0.5 bg-white transition-all" />
\<span className="block w-6 h-0.5 bg-white transition-all" />
\<span className="block w-6 h-0.5 bg-white transition-all" />
\</button>
\</header>
{/\* Mobile Menu \*/}
\<div className={\`fixed inset-0 bg-black bg-opacity-95 z-40 md:hidden flex-col items-center justify-center transition-all duration-300 ${isMenuOpen ? 'flex' : 'hidden'}\`}>
\<button
className="absolute top-8 right-8 text-3xl text-white"
onClick={() => setIsMenuOpen(false)}
aria-label="Cerrar menú"
>
✕
\</button>
\<nav className="flex flex-col items-center gap-8 text-2xl font-semibold">
{links.map((link, idx) => (
\<a
key={idx}
href={link.url?.href \|\| '#'}
target={link.url?.open\_in\_new\_tab ? '\_blank' : '\_self'}
rel={link.url?.no\_follow ? 'nofollow' : undefined}
className="hover:text-\[#A3FF12] transition-colors duration-200"
onClick={() => setIsMenuOpen(false)}
>
{link.text}
\</a>
))}
\</nav>
\</div>
{/\* Hero + Form \*/}
\<section className="flex flex-col md:flex-row justify-between items-center gap-6 px-6 md:px-8 max-w-[1440px] mx-auto min-h-60vh py-12">
\<div className="flex flex-col gap-4 md:w-1/2 w-full">
\<h1 className="text-white text-7xl font-bold max-w-[600px] font-montserrat">{title}\</h1>
\<p className="text-white text-xl max-w-[600px] font-montserrat">{description}\</p>
\</div>
\<div className="flex flex-col justify-center gap-4 md:w-1/2 w-full">
{formLoading && (
\<div className="flex items-center justify-center p-8">
\<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-white">\</div>
\<span className="ml-3 text-white">Loading form...\</span>
\</div>
)}
\<div ref={formRef} className="min-h-[200px] flex items-center justify-center">\</div>
\</div>
\</section>
\</div>
)
}
/* ----------- FIELDS ----------- */
export const fields = (
<ModuleFields>
\<TextField name="title" label="Title" default="Welcome to Supertek" />
\<TextField name="description" label="Description" default="Experts in ASIC repair and crypto mining technology." />
\<BooleanField name="useBackground" label="Use Background Image or GIF?" default={false} />
\<ImageField name="backgroundImage" label="Background Image or GIF" />
\<RepeatedFieldGroup
name="links"
label="Navigation Links"
occurrence={{ min: 1, default: 5 }}
default={\[
{ text: 'Services', url: { url: { href: '#' }, open\_in\_new\_tab: false, no\_follow: false } },
{ text: 'About', url: { url: { href: '#' }, open\_in\_new\_tab: false, no\_follow: false } },
{ text: 'Team', url: { url: { href: '#' }, open\_in\_new\_tab: false, no\_follow: false } },
{ text: 'Testimonials', url: { url: { href: '#' }, open\_in\_new\_tab: false, no\_follow: false } },
{ text: 'FAQs', url: { url: { href: '#' }, open\_in\_new\_tab: false, no\_follow: false } },
]}
>
\<TextField name="text" label="Link Text" required default="Link" />
\<LinkField
name="url"
label="Link URL"
supportedTypes={\[
'EXTERNAL', 'CONTENT', 'FILE', 'EMAIL\_ADDRESS', 'BLOG',
'CALL\_TO\_ACTION', 'PHONE\_NUMBER', 'WHATSAPP\_NUMBER', 'PAYMENT',
]}
showAdvancedRelOptions={true}
default={{
url: { content\_id: null, type: 'EXTERNAL', href: '' },
open\_in\_new\_tab: false,
no\_follow: false,
}}
/>
\</RepeatedFieldGroup>
\<FormField
id="idNumber"
name="form\_field\_name"
label="Form"
required={false}
locked={false}
disableInlineFormEditing={true}
requiredPropertyTypes={\['TICKET', 'COMPANY', 'CONTACT']}
supportAllWebinarTypes={true}
embedVersions={\['v2', 'v4']}
default={{
response\_type: 'inline',
message: 'Thanks for submitting the form.',
}}
/>
</ModuleFields>
)
/* ----------- META ----------- */
export const meta = {
label: ‘Header with Navigation, Text and Form’,
category: ‘headers’
}
export default Component
setIsMenuOpen(false)} aria-label=“Cerrar menú” > ✕{links.map((link, idx) => ( setIsMenuOpen(false)} > {link.text} ))}{/* Hero + Form */}
{title}
{description}
{formLoading && (
Loading form…)}
) } /* ----------- FIELDS ----------- */ export const fields = ( ) /* ----------- META ----------- */ export const meta = { label: ‘Header with Navigation, Text and Form’, category: ‘headers’ } export default Component