Skip to main content

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:
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:
OptionTypeRequiredDescription
nameReactFormIdsKeysYesThe screen to start on. See Screens.
mode'individual'NoVerification mode. Defaults to 'individual' for personal KYC.
type'ocr' | 'manual' | 'doc_upload'NoConfiguration type. Determines the verification flow pattern. Primarily affects the Document Selection, Personal Details, Review, and 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 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.
const sdk = await OneSdk({
  session: { token: 'your-token' },
  recipe: {
    form: {
      provider: {
        name: 'react',
        googleApiKey: 'your-google-api-key',
        useGoogleAutoCompleteSuggestion: true
      }
    }
  }
});

Recipe Options

PropertyTypeRequiredDescription
provider.name'react'YesMust be 'react' for the React form provider.
provider.googleApiKeystringNoGoogle API key with the Places API enabled. Enables address autocomplete on address field types. Google Maps is optional — when no key is provided, users enter their address manually. Load the Google Maps JS API (<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY&libraries=places"></script>) before initializing OneSdk.
provider.useGoogleAutoCompleteSuggestionbooleanNoDefault: false. When true, uses the newer AutocompleteSuggestion API instead of the deprecated AutocompleteService. As of March 1, 2025, Google deprecated AutocompleteService for new customers — set this to true for new integrations.
docUploadobjectNoDocument upload configuration. See Document Upload Configuration.

Methods

mount()

Mounts the Form component to a DOM element. Signature:
mount(mountElement: string | HTMLElement): Promise<WrapperContext>
Parameters:
ParameterTypeRequiredDescription
mountElementstring | HTMLElementYesCSS 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:
// 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:
unmount(): void
Example:
formComponent.unmount();

provider

Read-only property indicating the current vendor. Type: 'react'
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:
EventParametersDescription
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:
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 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:
StageDescription
readyScreen is ready to be displayed
loadedScreen has been rendered
failedScreen failed to load
successScreen action completed successfully (review, result, doc_upload only)
partialPartial verification result (review, result only)
pendingVerification pending (review, result only)
backUser navigated back (document only)
navigateUser navigated to another screen (document, doc_upload only)
form:review:* events require customResult: trueThe 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.
Event Payload: All screen events emit an EventPayload:
{
  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

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('Review screen ready');
  });

  formComponent.on('form:review:success', (payload) => {
    console.log('Review submitted successfully');
  });

  formComponent.on('form:review:partial', (payload) => {
    console.log('Partial match - additional verification needed');
  });

  formComponent.on('form:result:success', (payload) => {
    console.log('Verification passed');
  });

  formComponent.on('form:result:pending', (payload) => {
    console.log('Verification pending review');
  });

  // 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 verification outcomes - Listen for success, partial, and pending on both form:review and form:result screens. Don’t assume verification always results in a clear pass/fail.
  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.
  5. Customize screens via page config, not DOM manipulation - Use the page configuration and CSS class keys 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:
#form-container {
  width: 100%;
  min-height: 600px;
}

Google address autocomplete not working

Ensure googleApiKey is set in the recipe and the Google Places API is enabled for the key. If using useGoogleAutoCompleteSuggestion, the API key must have the Places API (New) library enabled.

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 and country-specific settings match the document types available in your flow.

Sub-Pages