Skip to content

Custom forms

The custom-form module renders an author-defined form as a step in the verification journey. The fields, labels, and copy are defined in your workflow template and delivered to the SDK; the module renders one control per field, collects the answers, uploads any files, and submits the step. On success it emits checktiv.custom_form.submitted so your page can advance.

Unlike the IDV module (which runs inside a sandboxed iframe), the custom-form module renders real form controls into your page. That means you must include its stylesheet.

Import the module for its self-registration side effect, and import the required stylesheet so the controls are styled:

import { init } from '@checktiv/sdk-web';
import '@checktiv/sdk-web/custom-form'; // registers the custom_form module
import '@checktiv/sdk-web/custom-form/style.css'; // required: styles the rendered controls

On the CDN script-tag path (window.Checktiv), the module is registered for you, and the stylesheet ships as a sibling file to <link> alongside the bundle.

The default path is mountProvisioned: when the server declares a custom_form step, the SDK renders it and injects the applicant-safe form config and copy for you.

const client = init({ publishableKey: 'ah_pk_us_test_...', getSessionToken });
client.mountProvisioned({
target: document.getElementById('verify-container'),
onEvent: (event) => {
if (event.type === 'checktiv.custom_form.submitted') {
// The step was accepted. Advance to the next step.
window.location.reload();
}
},
});

If you resolve the applicant-safe config yourself (for example, a host that renders the form on a step it already controls), mount the module explicitly and pass the config and copy:

client.mount('custom_form', {
target: document.getElementById('verify-container'),
config, // the applicant-safe form config: { fields, supportedLocales }
copy, // per-field and chrome strings, resolved to the applicant's locale
onEvent: (event) => {
if (event.type === 'checktiv.custom_form.submitted') {
window.location.reload();
}
},
});

The module is locale-agnostic by design. It never reads navigator.language or bundles a translation runtime. Instead:

  • Config ({ fields, supportedLocales }) is the applicant-safe form definition. Author-only fields (rules, notification targets) are stripped before they reach the browser, so nothing sensitive is rendered.
  • Copy is a map of plain strings your host already resolved to the applicant’s locale (for example, field.label[locale]). Absent keys fall back to a built-in English table, which is what a CDN script-tag customer gets.

Every author-supplied string renders as plain text, never as HTML, so author copy cannot inject markup into your page.

The module emits three events, all in the checktiv.custom_form.* namespace:

Event type Meaning
checktiv.custom_form.ready The form config resolved and the fields rendered. The applicant can begin.
checktiv.custom_form.submitted The step submit succeeded. Advance the journey (for example, reload into the next step). This is terminal for the step, not a verdict: rule evaluation happens on the server.
checktiv.custom_form.error A failure (session unresolved, upload failed, submit failed). Carries an actionable error.

Do not exhaustively switch on event.type. New event types may be added without a major version bump. See Versioning.

A screen with zero input fields (only content blocks, such as a disclosure to acknowledge) still renders a Continue control. Pressing it submits an empty answer set and advances the journey. This is intentional: without a Continue control, a content-only step would never complete and the workflow would wait forever.

When a field accepts a file, the module uploads the file from the browser directly to storage before it submits the answers, so file bytes never pass through your server. If an upload fails, the module emits checktiv.custom_form.error with upload_failed; the applicant can retry.