# Form Component

A form component that dynamically renders either a v4 form or a legacy form based on the form field's `embed_version` value. The component uses JavaScript islands to load and embed HubSpot forms client-side.

## Import path
```tsx
import Form from '@hubspot/cms-component-library/Form';
```

## Purpose

The Form component provides a unified interface for embedding HubSpot forms in CMS pages. It automatically determines whether to render a v4 form (using the new embed SDK) or a legacy form (using the classic `hbspt.forms.create` API) based on the `embed_version` returned by the form field. This allows module authors to simply pass the form field value through without needing to know which form version they're working with.

## Component Structure

```
Form/
├── index.tsx                          # Main component with version resolution logic
├── types.ts                           # TypeScript type definitions (discriminated union)
├── ContentFields.tsx                  # HubSpot field definitions for content
├── StyleFields.tsx                    # HubSpot field definitions for styling
├── islands/
│   ├── FormIsland.tsx                 # V4 form island (embed SDK)
│   ├── LegacyFormIsland.tsx           # Legacy form island (hbspt.forms.create)
│   ├── PlaceholderFormIsland.tsx      # Editor-only placeholder form
│   ├── index.module.scss              # Shared form styles
│   ├── v4Form.module.scss             # V4 form CSS variables
│   ├── legacyForm.module.scss         # Legacy form styles
│   └── PlaceholderForm.module.scss    # Placeholder form styles
└── llm.txt
```

## Props

The Form component uses a discriminated union — you must use one of two prop patterns:

### With form field (preferred)
```tsx
{
  formField: typeof FormFieldDefaults;  // The form field value from module props
  variant?: string;                     // Variant name passed to the island (default: 'form1')
}
```

### With explicit form ID and version
```tsx
{
  formId: string;                        // The HubSpot form ID
  formVersion: 'v4' | 'v3' | 'v2' | ''; // The form embed version
  variant?: string;                      // Variant name passed to the island (default: 'form1')
}
```

## Dynamic Version Resolution

When using the `formField` prop, the component reads `formField.embed_version` to decide which island to render:
- If `embed_version === 'v4'` → renders `FormIsland` (v4 embed SDK)
- Otherwise (missing or any other value) → renders `LegacyFormIsland` (classic embed)

When using `formId` + `formVersion` props, the `formVersion` value is used directly.

## Usage Examples

### Using form field (recommended)

This is the preferred approach. Pass the form field value directly and let the component resolve the version automatically.

Module file:
```tsx
import Form from '@hubspot/cms-component-library/Form';
import { FormFieldDefaults } from '@hubspot/cms-components/fields';

type ComponentProps = {
  form: typeof FormFieldDefaults;
};

export const Component = (props: ComponentProps) => {
  return <Form formField={props.form} />;
};
```

### Using explicit form ID and version

Use this when you have a form ID from a source other than a form field.

```tsx
import Form from '@hubspot/cms-component-library/Form';

<Form formId="53e5b258-4526-4012-9274-8bbe23ab2d09" formVersion="v4" />
```

## HubSpot CMS Integration

### Field Definitions

The Form component provides field definitions for easy integration with HubSpot CMS modules.

#### ContentFields

Configurable props for customizing field labels, names, and defaults:

```tsx
<Form.ContentFields
  formIdLabel="Form"
  formIdName="form"
  formIdDefault={{}}
/>
```

**Fields:**
- `form`: FormField that allows the user to select a HubSpot form in the editor. Supports embed versions v4, v3, and v2.

**ContentFields Props:**
```tsx
{
  formIdLabel?: string;              // Label shown in the editor (default: "Form")
  formIdName?: string;               // Field name (default: "form")
  formIdDefault?: FormFieldDefaults; // Default field value (default: {})
}
```

#### StyleFields

Configurable props for variant selection:

```tsx
<Form.StyleFields
  formVariantLabel="Form style"
  formVariantName="formVariant"
  formVariantDefault={{ variant_name: 'form1' }}
/>
```

**Fields:**
- `formVariant`: VariantSelectionField for selecting a form style variant from the `form` variant definition.

**StyleFields Props:**
```tsx
{
  formVariantLabel?: string;                     // Label shown in the editor (default: "Form style")
  formVariantName?: string;                      // Field name (default: "formVariant")
  formVariantDefault?: { variant_name: string }; // Default variant (default: { variant_name: 'form1' })
}
```

### Module Usage Example

```tsx
// Component file (index.tsx)
import Form from '@hubspot/cms-component-library/Form';
import { FormFieldDefaults } from '@hubspot/cms-components/fields';

type ComponentProps = {
  form: typeof FormFieldDefaults;
};

export const Component = (props: ComponentProps) => {
  return <Form formField={props.form} />;
};

// Fields file (fields.tsx)
import { ModuleFields, FieldGroup } from '@hubspot/cms-components/fields';
import Form from '@hubspot/cms-component-library/Form';

export const fields = (
  <ModuleFields>
    <Form.ContentFields />
    <FieldGroup label="Design" name="groupDesign" tab="STYLE">
      <Form.StyleFields />
    </FieldGroup>
  </ModuleFields>
);
```

## Islands

The Form component renders as a JavaScript island. Both form types require client-side JavaScript:

- **FormIsland (v4)**: Loads the v4 embed SDK script (`js.hsforms.net/forms/embed/developer/{portalId}.js`) and renders a `div` with `data-form-id`, `data-portal-id`, `data-env`, and `data-form-variant` attributes.
- **LegacyFormIsland**: Loads the legacy embed script (`js.hsforms.net/forms/embed/v2.js`) and calls `window.hbspt.forms.create()` to render the form into a target container. The container div also has `data-form-variant`.
- **PlaceholderFormIsland**: Renders a static, disabled placeholder form (with dummy first name, last name, email fields and a submit button). It is only ever reached when the user is in the editor and no form ID is present — `FormComponent` itself returns `null` in that same situation outside the editor.

All islands automatically resolve the portal ID and environment (QA vs prod) from the CMS context.

## Best Practices

- **Prefer `formField` over `formId` + `formVersion`**: Passing the form field value directly ensures the version is always correct and keeps the module code simple.
- **Form version is determined by the form itself**: The `embed_version` property on the form field value is set by HubSpot based on the form's configuration. Module authors should not hardcode a version.
- **Styling via variant definitions**: Use `Form.StyleFields` with variant definitions to allow theme-level form styling rather than hardcoding CSS values.
