GenZformHelp Center
IntegrationsEmbed Guides

Embed in Next.js

Add GenZform forms to Next.js applications with proper client component patterns and Script optimization.

GenZform forms work with Next.js App Router and Pages Router. This guide covers client components, Script optimization, and server-side considerations.

Client Component (App Router)

Since embeds require browser APIs, create a client component:

// components/GenZformEmbed.tsx
'use client';

import Script from 'next/script';

interface GenZformEmbedProps {
  formId: string;
  height?: number | string;
  minHeight?: number;
  className?: string;
  locale?: string;
}

export function GenZformEmbed({
  formId,
  height = 500,
  minHeight,
  className,
  locale = 'en',
}: GenZformEmbedProps) {
  return (
    <>
      <iframe
        data-genz-form={formId}
        data-embed-style="standard"
        data-min-height={minHeight}
        src={`https://genzform.com/f/${formId}?locale=${locale}`}
        style={{
          width: '100%',
          height: typeof height === 'number' ? `${height}px` : height,
          border: 'none',
        }}
        className={className}
        title="GenZform"
      />
      <Script
        src="https://genzform.com/embed-v1.js"
        strategy="lazyOnload"
      />
    </>
  );
}

Use it in any page or layout:

// app/contact/page.tsx
import { GenZformEmbed } from '@/components/GenZformEmbed';

export default function ContactPage() {
  return (
    <main>
      <h1>Contact Us</h1>
      <GenZformEmbed formId="your-form-id" height={600} />
    </main>
  );
}
// components/GenZformPopup.tsx
'use client';

import Script from 'next/script';
import { useEffect, useState } from 'react';

interface GenZformPopupProps {
  formId: string;
  children: React.ReactNode;
  width?: number;
  darkOverlay?: boolean;
  openOnLoad?: boolean;
  openDelay?: number;
  className?: string;
}

export function GenZformPopup({
  formId,
  children,
  width = 450,
  darkOverlay = true,
  openOnLoad = false,
  openDelay = 0,
  className,
}: GenZformPopupProps) {
  const [scriptLoaded, setScriptLoaded] = useState(false);

  useEffect(() => {
    if (scriptLoaded) {
      // Register popup buttons after script loads
      (window as any).GenZEmbed?.registerPopups?.();
    }
  }, [scriptLoaded]);

  return (
    <>
      <button
        data-genz-form={formId}
        data-embed-style="popup"
        data-width={width}
        data-dark-overlay={darkOverlay}
        data-popup-open-on-load={openOnLoad}
        data-popup-delay={openDelay}
        className={className}
      >
        {children}
      </button>
      <Script
        src="https://genzform.com/embed-v1.js"
        strategy="lazyOnload"
        onLoad={() => setScriptLoaded(true)}
      />
    </>
  );
}

Usage:

<GenZformPopup
  formId="your-form-id"
  darkOverlay={true}
  className="bg-green-600 text-white px-4 py-2 rounded"
>
  Get Started
</GenZformPopup>

Full Page Form

For dedicated form pages that fill the viewport:

// components/GenZformFullPage.tsx
'use client';

import Script from 'next/script';

export function GenZformFullPage({
  formId,
  locale = 'en',
}: {
  formId: string;
  locale?: string;
}) {
  return (
    <div className="fixed inset-0">
      <iframe
        data-genz-form={formId}
        data-embed-style="full_page"
        src={`https://genzform.com/f/${formId}?locale=${locale}`}
        className="w-full h-full border-none"
        title="GenZform"
      />
      <Script src="https://genzform.com/embed-v1.js" strategy="lazyOnload" />
    </div>
  );
}

Pages Router

For the Pages Router, use next/script the same way:

// pages/contact.tsx
import Script from 'next/script';

export default function ContactPage() {
  return (
    <>
      <main>
        <h1>Contact Us</h1>
        <iframe
          data-genz-form="your-form-id"
          data-embed-style="standard"
          src="https://genzform.com/f/your-form-id"
          style={{ width: '100%', height: '500px', border: 'none' }}
          title="GenZform"
        />
      </main>
      <Script
        src="https://genzform.com/embed-v1.js"
        strategy="lazyOnload"
      />
    </>
  );
}

Script Loading Strategies

Next.js Script component supports different loading strategies:

StrategyUse When
lazyOnloadDefault. Loads after page is interactive. Best for most forms.
afterInteractiveLoads immediately after page becomes interactive. Use for above-the-fold forms.
beforeInteractiveLoads before page hydration. Rarely needed for forms.
// For forms immediately visible on page load
<Script
  src="https://genzform.com/embed-v1.js"
  strategy="afterInteractive"
/>

Dynamic Form Loading

Load forms dynamically based on route or user action:

'use client';

import dynamic from 'next/dynamic';

const GenZformEmbed = dynamic(
  () => import('@/components/GenZformEmbed').then(mod => mod.GenZformEmbed),
  { ssr: false }
);

export default function DynamicFormPage({ formId }: { formId: string }) {
  return <GenZformEmbed formId={formId} />;
}

With Internationalization

Pass the locale from your i18n setup:

// app/[locale]/contact/page.tsx
import { GenZformEmbed } from '@/components/GenZformEmbed';

export default function ContactPage({
  params: { locale },
}: {
  params: { locale: string };
}) {
  return (
    <GenZformEmbed
      formId="your-form-id"
      locale={locale}
    />
  );
}

Frequently Asked Questions

Why do I need 'use client'?

The embed script and iframe interactions require browser APIs. Next.js App Router components are server components by default, so you need 'use client' to access browser features.

Can I use the form in a Server Component?

Not directly. Wrap the form in a client component and import that into your server component. The form itself needs browser APIs to function.

Does the Script component prevent duplicate loading?

Yes. Next.js Script component automatically deduplicates scripts with the same src, even if you include the component multiple times.

How do I handle form submission callbacks?

See the Custom JavaScript guide for listening to form events and handling submissions.


On this page