# Embedding forms in React

## Iframe embed

The plain [iframe embed](/embeds/iframe-embed) needs no special handling; render it like any other element. JSX uses camelCase for the boolean attributes and an object for `style`:

```jsx
function CakeOrderForm() {
  return (
    <iframe
      title="Cake Order Form"
      src="https://eu.forms.app/form/69d4bd130b443bda40c8f65a"
      allowTransparency
      allowFullScreen
      allow="geolocation; microphone; camera"
      style={{ width: '100vw', minWidth: '100%', height: 600, border: 'none' }}
    />
  );
}
```

## Script embed

The [script embed](/embeds/script-embed)'s `onload` inline attribute isn't idiomatic in React. Instead, load `embed.js` in a `useEffect`, and call `new window.formsapp(...)` once it's ready. A small hook keeps the script from being injected more than once if you render several widgets:

```jsx
import { useEffect, useState } from 'react';

function useFormsAppScript() {
  const [ready, setReady] = useState(() => typeof window !== 'undefined' && !!window.formsapp);

  useEffect(() => {
    if (window.formsapp) {
      setReady(true);
      return;
    }
    const existing = document.querySelector('script[src="https://cdn.formsapp.io/embed.js"]');
    if (existing) {
      existing.addEventListener('load', () => setReady(true));
      return;
    }
    const script = document.createElement('script');
    script.src = 'https://cdn.formsapp.io/embed.js';
    script.async = true;
    script.defer = true;
    script.onload = () => setReady(true);
    document.body.appendChild(script);
  }, []);

  return ready;
}
```

Use it in a component that renders a pop-up trigger:

```jsx
function CakeOrderPopup() {
  const ready = useFormsAppScript();

  useEffect(() => {
    if (!ready) return;
    new window.formsapp(
      '69d4bd130b443bda40c8f65a',
      'popup',
      {
        overlay: 'rgba(45,45,45,0.5)',
        button: { color: '#ff9e24', text: 'Click here!' },
        width: '800px',
        height: '600px',
        openingAnimation: { entrance: 'animate__fadeIn', exit: 'animate__fadeOut' },
      },
      'https://eu.forms.app',
    );
  }, [ready]);

  return <button formsappid="69d4bd130b443bda40c8f65a" />;
}
```

Attribute casing
HTML attribute names are case-insensitive, so `formsappid` and `formsappId` resolve to the same DOM attribute. React only recognizes the lowercase spelling for unknown attributes and otherwise logs a harmless development warning, so write it as `formsappid` in JSX.

## Passing data from a URL query parameter

Combine the hook above with `URLSearchParams` and the `answers` option from [Passing data to your form](/embeds/passing-form-data):

```jsx
function ReferralForm() {
  const ready = useFormsAppScript();
  const [ref] = useState(() => new URLSearchParams(window.location.search).get('ref') ?? '');

  useEffect(() => {
    if (!ready) return;
    new window.formsapp(
      '69d4bd130b443bda40c8f65a',
      'standard',
      {
        width: '100vw',
        height: 'formHeight',
        answers: { '63ebad419442ad0448b9e9b6': ref },
      },
      'https://eu.forms.app',
    );
  }, [ready, ref]);

  return <div data-formsapp-src="https://eu.forms.app/form/69d4bd130b443bda40c8f65a" />;
}
```

## What's next

- [Next.js](/embeds/examples/nextjs) for the App Router equivalent, including `next/script`.
- [Embed options](/embeds/embed-options) for every layout's settings.