Developer guide

Next.js: Events

Events let your application observe field changes, resets, validation results, and configured email delivery. This page shows the API and examples for Next.js.

EventNext.js bindingPayloadWhen
inputinputUserDataEmitted when a field interaction is committed. Text-like controls emit on blur.
resetresetvoidEmitted after the renderer clears the form model values.
submitsubmitSubmitDataEmitted after validation for every submit attempt, including an 'invalid' attempt.
mail-sendmailSend{ success: boolean }Emitted after email delivery for a valid form finishes, when email delivery is configured.

Payload types

TypeScript projects can import these definitions from @jcees-forms/types/interfaces/data. Add @jcees-forms/types as a direct development dependency when your package manager does not expose transitive dependencies.

npm install --save-dev @jcees-forms/types
type FieldValue =
  | string
  | number
  | string[]
  | number[]
  | Record<string, boolean>

interface UserData {
  id: string
  label: string
  value: FieldValue
  visible: boolean
  invalid: boolean
  errors: string[]
}

interface SubmitData {
  status: 'valid' | 'invalid'
  items: UserData[]
}

input: one field

The input callback receives one UserData object. Text, textarea, password, and date controls generally publish the value when the control is blurred. Lists, ranges, and selects publish when their selection is committed.

PropertyTypeMeaning
idstringThe stable ID of the form field.
labelstringThe field title configured in the form builder.
valueFieldValueThe current value. Its shape depends on the control.
visiblebooleanWhether visibility rules currently show the field.
invalidbooleanWhether the field failed validation.
errorsstring[]The current human-readable validation messages.
{
  id: 'email',
  label: 'Email address',
  value: 'person@example.com',
  visible: true,
  invalid: false,
  errors: []
}

submit: validation status and all fields

The submit callback runs for every attempt. Always inspect status before sending data to your own API. The items array contains every field; use each item's visible flag if hidden fields should be excluded by your application.

{
  status: 'valid',
  items: [
    {
      id: 'field-id',
      label: 'Email address',
      value: 'person@example.com',
      visible: true,
      invalid: false,
      errors: []
    }
  ]
}
{
  status: 'invalid',
  items: [{
    id: 'email',
    label: 'Email address',
    value: '',
    visible: true,
    invalid: true,
    errors: ['Email address is required']
  }]
}

reset: no payload

The callback is invoked without arguments after the renderer clears its model values. Use it to clear related application state or analytics.

mail-send: delivery result

This event only follows a valid submission when the published form has email delivery configured. It is not emitted for an invalid submission or a form without email settings.

{ success: true }
// or
{ success: false }

In the current renderers, success: false means the email workflow threw an exception. success: true means that workflow completed; provider-level failures returned without an exception may still be logged separately.

Submit and email are separate

submit reports form validation immediately. mail-send reports the later email step. A valid submit therefore does not by itself confirm email delivery.

Next.js App Router

Event handlers are functions, so they cannot be passed to the async server component. Load the form in the server page and pass the serializable form data to a client component that owns the callbacks.

// app/contact/page.tsx — Server Component
import { loadJCeesFormData } from '@jcees-forms/next/server'
import ContactForm from './ContactForm'

export default async function Page() {
  const initialFormData = await loadJCeesFormData({
    space: 'your-space-id',
    form: 'your-form-id'
  })

  return <ContactForm initialFormData={initialFormData} />
}
// app/contact/ContactForm.tsx — Client Component
'use client'

import { JCeesFormsClient } from '@jcees-forms/next/client'

export default function ContactForm({ initialFormData }) {
  return (
    <JCeesFormsClient
      space="your-space-id"
      form="your-form-id"
      initialFormData={initialFormData}
      input={(field) => console.log('changed', field)}
      reset={() => console.log('reset')}
      submit={(result) => console.log('submitted', result)}
      mailSend={(result) => console.log('mail sent', result.success)}
    />
  )
}

Next.js Pages Router

import { getJCeesFormProps } from '@jcees-forms/next/server'
import { JCeesFormsClient } from '@jcees-forms/next/client'

export const getServerSideProps = () => getJCeesFormProps({
  space: 'your-space-id',
  form: 'your-form-id'
})

export default function ContactPage(props) {
  return (
    <JCeesFormsClient
      {...props}
      input={(field) => console.log('changed', field)}
      reset={() => console.log('reset')}
      submit={(result) => console.log('submitted', result)}
      mailSend={(result) => console.log('mail sent', result.success)}
    />
  )
}