Skip to content

useSnipForm

import { useSnipForm } from '@snipform/react';
import type { Fields } from '@snipform/react';
const fields: Fields = {
email: { type: 'email', rules: { required: 'Email is required', email: null } },
plan: { type: 'select', initial: 'starter' },
};
const form = useSnipForm({ key: 'YOUR_FORM_KEY', fields });

The hook returns a SnipFormHandle. Call it once per form, at the top of the component that renders it.

OptionTypeDefault
keystringrequiredThe form key from the dashboard.
fieldsFieldsrequiredEvery field the form can submit. Sent to the server at init and frozen. See field config.
validateOn'submit' | 'blur''submit'blur validates each field on the server as the visitor leaves it. Validation
initOn'interaction' | 'mount''interaction'When the server session opens. mount opens it immediately and is scored as bot-like; avoid it. Spam protection
apiBasestringhttps://api.snipform.io/v2API base URL.
onSuccess(result: SubmitSuccess) => voidCalled after a successful submit.
onValidationError(errors: FieldErrors) => voidCalled when a submit fails validation.
onError(error: SnipFormError) => voidCalled on any init or submit failure, fatal or recoverable.
type Fields = Record<string, {
type?: FieldType; // default 'text'
rules?: RuleMessages; // { ruleName: message | null }
initial?: string | string[];
}>;
Key
typeOne of text email tel url number password hidden date textarea select select-multiple radio checkbox. Drives how register() binds the input and how the server reads the value. checkbox and select-multiple produce arrays.
rulesRule name to message. null uses the server’s default message. Parameters go in square brackets: 'max_length[120]'. A field with no rules is optional and accepts anything.
initialStarting value. Defaults to '', or [] for checkbox and select-multiple.
PropertyType
statusStatus'idle' | 'initializing' | 'ready' | 'submitting' | 'success' | 'error' | 'fatal'. See lifecycle.
valuesRecord<string, string | string[]>Current values keyed by field name.
errorsFieldErrors{ field: [message, ...] }. Every message the server returned, not just the first.
fatalstring | nullThe form cannot run: bad key, unpublished form, domain not allowed, unknown rule name. Show this instead of the form.
errorSnipFormError | nullA recoverable failure from the last init or submit (network, 403, 5xx).
successSubmitSuccess | null{ html, values } after a successful submit. html is the form’s thank-you content with %field% variables already substituted by the server.
branding{ label, link } | nullPresent when the plan requires a “powered by” link. Render with <Branding>.
isReadybooleanstatus === 'ready'
isSubmittingbooleanstatus === 'submitting'
Method
register(name, { value? })Props for an input, select or textarea bound to name. Pass value for each option of a checkbox group or radio set. Inputs
setValue(name, value)Set a value programmatically. Counts as touching the field.
fieldError(name)The first message for a field, or undefined.
submit()Submit now. Returns Promise<void>; outcomes land on the handle. Opens the session first if none is open. No-op while submitting or fatal.
handleSubmit(event)submit() wrapped with preventDefault(). <SnipForm> wires this to onSubmit.
validate(field?)Server-validate the current values without submitting. Returns the error bag and applies it: all fields, or only field when given. Resolves to {} when no session is open.
reset()Back to idle: initial values, no errors, no success, session dropped. The next interaction opens a new session.
Property
formPropsSpread onto your own <form> when you do not use <SnipForm>: ref, noValidate, onSubmit, and capture-phase onFocusCapture / onClickCapture / onKeyDownCapture / onTouchStartCapture that open the human gate. The ref is also what lets the hook notice the form scrolling into view.
honeypotPropsnull until the session is open, then props for the bot-trap input: name, value: '', tabIndex: -1, autoComplete: 'off', aria-hidden, readOnly, and an off-screen style. Spread onto an <input> or render <Honeypot form={form} />.
// Equivalent to <SnipForm form={form}>...</SnipForm>
<form {...form.formProps} className="space-y-4">
...
<Honeypot form={form} />
</form>
idle ──(first interaction)──▶ initializing ──▶ ready ──(submit)──▶ submitting ──▶ success
│ │
▼ ├──▶ ready (validation errors)
fatal └──▶ error (network, 403, 5xx)
StatusMeaningTypical render
idleMounted, no session yet. Nothing has been sent.The form, fully interactive.
initializingFirst interaction happened, session opening.The form. Inputs keep working; values are kept.
readySession open. Also the state after a validation failure.The form, with errors if any.
submittingRequest in flight.Disable the button: disabled={form.isSubmitting}.
successSubmitted. The session is consumed.success.html or your own thank-you.
errorA recoverable failure. error holds the reason. Submitting again is allowed.The form plus a retry message.
fatalThe form cannot run. fatal holds the server’s message.The message instead of the form.

The session that initializing opens is the one described in How Forms Work: it lives 600 seconds, is pinned to the visitor’s connection and is consumed by a successful submit. When a submit hits an expired session the hook opens a new one and retries once, transparently.

Everything is exported:

import type {
SnipFormOptions, SnipFormHandle, Fields, FieldConfig, FieldType, FieldValue,
RuleMessages, FieldErrors, FieldProps, FormProps, HoneypotProps, RegisterOptions,
Status, SubmitSuccess, ErrorKind, BrandingInfo,
} from '@snipform/react';
import { SnipFormError } from '@snipform/react';

SnipFormError carries message, kind ('fatal' | 'expired' | 'unauthorized' | 'network' | 'server') and the HTTP status when there was one. What each kind means is covered in States.