> ## Documentation Index
> Fetch the complete documentation index at: https://docs.frankieone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Form Module

> Pre-built eKYC form UI for identity verification

## Overview

The Form module provides a complete pre-built eKYC form UI that guides users through the identity verification process. It handles the full flow from welcome screen through document selection, data entry, review, submission, and results - all with a single component.

The form module supports three configuration types:

* **OCR** - Document capture with automatic data extraction
* **Manual** - Manual data entry by the user
* **Doc Upload** - Document file upload for verification

## Accessing the Module

The Form module is accessed through the SDK's component factory using the React provider:

```javascript theme={null}
const sdk = await OneSdk({
  mode: 'production',
  session: { token: 'your-token' }
});

const formComponent = sdk.component('form', {
  name: 'WELCOME',
  mode: 'individual',
  type: 'manual'
});
```

## Configuration

### Module Options

Options are passed during module initialization:

| Option | Type                                | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ------ | ----------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | `ReactFormIdsKeys`                  | Yes      | The screen to start on. See [Screens](/docs/sdk-reference/form-module/screens).                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `mode` | `'individual'`                      | No       | Verification mode. Defaults to `'individual'` for personal KYC.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `type` | `'ocr' \| 'manual' \| 'doc_upload'` | No       | Configuration type. Determines the verification flow pattern. Primarily affects the [Document Selection](/docs/sdk-reference/form-module/screens#document-selection), [Personal Details](/docs/sdk-reference/form-module/screens#personal-details), [Review](/docs/sdk-reference/form-module/screens#review), and [Retry](/docs/sdk-reference/form-module/screens#retry) screens. Static screens (Welcome, Consent, Start) and progress screens (Loading, Result) are not affected. Doc upload screens are only shown when `type` is `'doc_upload'`. |

The module options also accept page-level configuration overrides. See [Configuration](/docs/sdk-reference/form-module/configuration) for all available customization options.

### Recipe Configuration

The Form module requires provider configuration in your recipe. Form configuration (screens, type, styling) is set through module options when calling `sdk.component('form', options)`, not in the recipe.

```javascript theme={null}
const sdk = await OneSdk({
  session: { token: 'your-token' },
  recipe: {
    form: {
      provider: {
        name: 'react',
        googleApiKey: 'your-google-api-key',
        useGoogleAutoCompleteSuggestion: true
      }
    }
  }
});
```

### Recipe Options

| Property                                   | Type      | Required | Description                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider.name`                            | `'react'` | Yes      | Must be `'react'` for the React form provider.                                                                                                                                                                                                                                                                                                    |
| `provider.googleApiKey`                    | `string`  | No       | Google API key that enables address autocomplete on `address` field types. Google Maps is optional — when no key is provided, users enter their address manually. The key must have **Geocoding API** and **Places API (New)** authorized. See [Google Maps setup](#google-maps-address-autocomplete) for GCP configuration steps.                |
| `provider.useGoogleAutoCompleteSuggestion` | `boolean` | No       | **Set to `true` for all integrations.** Switches from the deprecated `AutocompleteService` to the newer `AutocompleteSuggestion` API. The deprecated path causes address search failures (`REQUEST_DENIED`) on API keys that restrict by service. Requires `@frankieone/one-sdk` **v1.8.2 or later** and **Places API (New)** enabled on the key. |
| `docUpload`                                | `object`  | No       | Document upload configuration. See [Document Upload Configuration](/docs/sdk-reference/form-module/configuration#document-upload-configuration).                                                                                                                                                                                                  |

### Google Maps Address Autocomplete

<Warning>
  **Action required for all integrations using address search.** Google's Geocoding API now returns `REQUEST_DENIED` for keys that do not have it explicitly authorized. Address search will silently fail until the key is updated. Follow the steps below.
</Warning>

Address autocomplete requires two APIs enabled on your Google Cloud API key:

| API                  | Why it's needed                                                                                                                                                                 |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Geocoding API**    | Resolves a selected suggestion into structured address components. Required by both the old and new autocomplete paths — address search fails with `REQUEST_DENIED` without it. |
| **Places API (New)** | Powers the `AutocompleteSuggestion` lookup when `useGoogleAutoCompleteSuggestion` is `true`.                                                                                    |

#### GCP setup steps

1. Open [Google Cloud Console → APIs & Services → Library](https://console.cloud.google.com/apis/library).
2. Search for and enable **Geocoding API**.
3. Search for and enable **Places API (New)**.
4. Go to **APIs & Services → Credentials** and open your API key.
5. Under **API restrictions → Restrict key**, add both **Geocoding API** and **Places API (New)** to the allowed list.
6. Save.

#### Script tag

Load the Maps JavaScript API **before** initializing OneSdk:

```html theme={null}
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY&loading=async&libraries=places"></script>
```

#### OneSDK recipe configuration

```javascript theme={null}
const sdk = await OneSdk({
  session: { token: 'your-token' },
  recipe: {
    form: {
      provider: {
        name: 'react',
        googleApiKey: 'YOUR_GOOGLE_API_KEY',
        useGoogleAutoCompleteSuggestion: true
      }
    }
  }
});
```

<Note>
  `useGoogleAutoCompleteSuggestion` requires `@frankieone/one-sdk` **v1.8.2 or later**. Run `npm install @frankieone/one-sdk@latest` to upgrade.
</Note>

***

## Methods

### `mount()`

Mounts the Form component to a DOM element.

**Signature:**

```typescript theme={null}
mount(mountElement: string | HTMLElement): Promise<WrapperContext>
```

**Parameters:**

| Parameter      | Type                    | Required | Description                                                                                          |
| -------------- | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `mountElement` | `string \| HTMLElement` | Yes      | CSS selector string (e.g., `'#form-container'`) or HTMLElement object where the form will be mounted |

**Returns:** `Promise<WrapperContext>` - Resolves when the form is mounted. The `WrapperContext` contains a `cleanup()` method.

**Example:**

```javascript theme={null}
// Mount to element by ID
await formComponent.mount('#form-container');

// Mount to element reference
const container = document.getElementById('form-container');
await formComponent.mount(container);
```

***

### `unmount()`

Unmounts the Form component from the DOM.

**Signature:**

```typescript theme={null}
unmount(): void
```

<Warning>
  `unmount()` clears **all content** from the element the component was mounted to — not just the component itself. If another component (e.g., an IDV flow) is sharing the same container, unmounting will destroy its content too. When you need to show a loading screen alongside another component, mount the loading screen to a **separate element** so that unmounting it does not affect the other component. See the [IDV with Review flow](/docs/embedded-flows/idv-review#loading-screens) for an example.
</Warning>

**Example:**

```javascript theme={null}
formComponent.unmount();
```

***

### `provider`

Read-only property indicating the current vendor.

**Type:** `'react'`

```javascript theme={null}
console.log(formComponent.provider); // 'react'
```

***

## Events

The Form module uses a structured event system with two levels:

### Global Events

These events apply to the form module as a whole:

| Event        | Parameters                           | Description                                                                                     |
| ------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------- |
| `ready`      | `{ domElement, config }`             | Form component is ready. Contains the mount element and resolved configuration.                 |
| `loaded`     | `{ domElement, provider }`           | Form component is loaded and rendered.                                                          |
| `results`    | `{ documents, applicant, entityId }` | Verification results received. Contains the submitted documents, applicant data, and entity ID. |
| `navigation` | `{ page }`                           | User navigated to a different screen. Contains the screen name.                                 |
| `destroy`    | (none)                               | Form component is being destroyed/unmounted.                                                    |

**Example:**

```javascript theme={null}
formComponent.on('ready', ({ domElement, config }) => {
  console.log('Form ready with config:', config);
});

formComponent.on('results', ({ documents, applicant, entityId }) => {
  console.log('Verification complete for:', entityId);
  console.log('Documents:', documents);
  console.log('Applicant:', applicant);
});

formComponent.on('navigation', ({ page }) => {
  console.log('User navigated to:', page);
});
```

### Screen Events

Each screen emits events following the pattern `form:{screen}:{stage}`. See [Screens](/docs/sdk-reference/form-module/screens) for the complete screen event reference.

**Event Pattern:**

```
form:welcome:ready
form:welcome:loaded
form:welcome:failed
form:consent:ready
form:review:success
form:result:pending
...
```

**Event Stages:**

| Stage      | Description                                                                                                                                                                              |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ready`    | User pressed the screen's CTA (call-to-action) button, completing the screen                                                                                                             |
| `loaded`   | Screen has been rendered                                                                                                                                                                 |
| `failed`   | Screen failed to load (except result — see [Result screen events](/docs/sdk-reference/form-module/screens#result))                                                                       |
| `success`  | CTA pressed on a SUCCESS-state result screen, or verification succeeded (review with [`customResult`](/docs/sdk-reference/form-module/configuration#page-configuration-types) only)      |
| `partial`  | CTA pressed on a PARTIAL-state result screen, or partial verification result (review with [`customResult`](/docs/sdk-reference/form-module/configuration#page-configuration-types) only) |
| `pending`  | CTA pressed on a PENDING-state result screen, or verification pending (review with [`customResult`](/docs/sdk-reference/form-module/configuration#page-configuration-types) only)        |
| `timeout`  | CTA pressed on a TIMEOUT-state result screen (result only)                                                                                                                               |
| `info`     | Non-fatal, informational screen event (result only) — currently emitted when a custom `resultImage` fails to load, before falling back to the default state icon                         |
| `back`     | User navigated back (document only)                                                                                                                                                      |
| `navigate` | User navigated to another screen (document, doc\_upload only)                                                                                                                            |

<Warning>
  **`form:review:*` events require `customResult: true`**

  The `form:review:success`, `form:review:failed`, `form:review:partial`, and `form:review:pending` events are **only emitted when `customResult: true` is set in manual mode**. When `customResult` is `false` (the default), the form automatically navigates to and displays the configured result screen without emitting these events.

  In OCR mode, the only terminal event is `ready` on the final screen.
</Warning>

**Event Payload:**

All screen events emit an `EventPayload`:

```typescript theme={null}
{
  componentName?: string;     // Module name
  provider?: string;          // Provider name ('react')
  inputInfo: {
    name?: string;            // Screen name (e.g., 'welcome', 'review')
    type?: string;            // Config type ('ocr', 'manual', 'doc_upload')
    documentType?: string;    // Document type if applicable
    index?: number;           // Document index if applicable
  }
}
```

***

## Complete Example

```javascript theme={null}
import OneSdk from '@frankieone/one-sdk';

async function startVerificationForm() {
  // Initialize SDK
  const sdk = await OneSdk({
    mode: 'production',
    session: { token: await getSessionToken() },
    recipe: {
      form: {
        provider: {
          name: 'react',
          googleApiKey: 'your-google-api-key',
          useGoogleAutoCompleteSuggestion: true
        }
      }
    }
  });

  // Create form component
  const formComponent = sdk.component('form', {
    name: 'WELCOME',
    mode: 'individual',
    type: 'manual'
  });

  // Global events
  formComponent.on('ready', ({ domElement, config }) => {
    console.log('Form ready');
  });

  formComponent.on('loaded', ({ domElement, provider }) => {
    console.log('Form loaded with provider:', provider);
  });

  // Track navigation
  formComponent.on('navigation', ({ page }) => {
    console.log('Current screen:', page);
    updateProgressBar(page);
  });

  // Screen-level events
  formComponent.on('form:welcome:loaded', (payload) => {
    console.log('Welcome screen displayed');
  });

  formComponent.on('form:consent:loaded', (payload) => {
    console.log('Consent screen displayed');
  });

  formComponent.on('form:document:loaded', (payload) => {
    console.log('Document selection displayed');
  });

  formComponent.on('form:review:ready', (payload) => {
    console.log('User pressed CTA on review screen');
  });

  // Review-level result events (only with customResult: true in manual mode)
  formComponent.on('form:review:success', (payload) => {
    console.log('Verification passed — handle custom result');
  });

  formComponent.on('form:review:partial', (payload) => {
    console.log('Partial match — handle custom result');
  });

  // Result screen CTA events (fired when user presses CTA on result screens)
  formComponent.on('form:result:success', (payload) => {
    console.log('User pressed CTA on SUCCESS result screen');
  });

  formComponent.on('form:result:pending', (payload) => {
    console.log('User pressed CTA on PENDING result screen');
  });

  // Final results
  formComponent.on('results', ({ documents, applicant, entityId }) => {
    console.log('Verification complete');
    console.log('Entity:', entityId);
    handleVerificationResult({ documents, applicant, entityId });
  });

  // Mount the form
  await formComponent.mount('#form-container');
}
```

***

## Best Practices

1. **Set up event listeners before mounting** - Register all event handlers before calling `mount()` to avoid missing early events like `ready` and `loaded`.

2. **Handle all result screen CTA events** - Listen for `form:result:success`, `form:result:partial`, `form:result:pending`, and `form:result:failed` to detect when the user dismisses a result screen. If using `customResult: true` on the review component, also handle the corresponding `form:review:*` events.

3. **Use the `navigation` event for progress tracking** - The global `navigation` event fires on every screen change, making it ideal for progress bars, analytics, and conditional UI outside the form.

4. **Configure `type` to match your flow** - Choose `'ocr'`, `'manual'`, or `'doc_upload'` based on your integration. The type determines which screens are shown and how data is collected. See [Configuration Types](/docs/sdk-reference/form-module/configuration#configuration-types).

5. **Customize screens via page config, not DOM manipulation** - Use the [page configuration](/docs/sdk-reference/form-module/configuration#page-configuration-types) and [CSS class keys](/docs/sdk-reference/form-module/configuration#css-styling) to customize appearance and content rather than manipulating the DOM directly.

***

## Common Issues

### Component not displaying

Ensure the mount element exists in the DOM before calling `mount()` and has sufficient size:

```css theme={null}
#form-container {
  width: 100%;
  min-height: 600px;
}
```

### Google address autocomplete not working

**Symptoms** — one or both of these appear in the browser console:

```
Geocoding Service: This API key is not authorized to use this service or API. Status: REQUEST_DENIED
```

```
google.maps.places.AutocompleteService is not available to new customers. Please use google.maps.places.AutocompleteSuggestion instead.
```

**Root causes:**

* `REQUEST_DENIED` — the API key does not have the **Geocoding API** authorized. Both the old and new autocomplete paths call the Geocoding API after retrieving suggestions; without it, address search returns nothing.
* `AutocompleteService` warning — `useGoogleAutoCompleteSuggestion` is not set to `true`. The deprecated `AutocompleteService` is unavailable on keys created after March 1, 2025 and will eventually be removed for all customers.

**Fix:**

1. In Google Cloud Console, enable **Geocoding API** and **Places API (New)** on the key and add both to the key's API restrictions allow-list. See [Google Maps setup](#google-maps-address-autocomplete).
2. Set `useGoogleAutoCompleteSuggestion: true` in the recipe's `form.provider` config.
3. Ensure `@frankieone/one-sdk` is **v1.8.2 or later** — upgrade with `npm install @frankieone/one-sdk@latest` if needed.

### Form fields not matching expected document type

The fields shown on the Review and Personal Details screens depend on the `type` option and the document type selected. Ensure your [form field configuration](/docs/sdk-reference/form-module/configuration#form-fields) and [country-specific settings](/docs/sdk-reference/form-module/configuration#country-specific-field-configuration) match the document types available in your flow.

***

## Sub-Pages

<CardGroup cols={2}>
  <Card title="Screens" icon="rectangle-list" href="/sdk-reference/form-module/screens">
    All 13 form screens, their events, and behavior
  </Card>

  <Card title="Configuration" icon="sliders" href="/sdk-reference/form-module/configuration">
    Page customization, CSS styling, document upload, and form fields
  </Card>
</CardGroup>

***

## Related

* [SDK Initialization](/docs/sdk-reference/sdk-initialization)
* [Individual Module](/docs/sdk-reference/individual-module)
* [OCR Module](/docs/sdk-reference/ocr-module)
* [IDV Module](/docs/sdk-reference/idv-module)
* [Event System](/docs/sdk-reference/events)
