Skip to main content

Form Builder

Imports

import { FormBuilder, MultiStepFormBuilder } from '@codella-software/utils'
import { useFormBuilder } from '@codella-software/react'
import * as yup from 'yup'

FormBuilder

FormBuilder is created with FormBuilder.create<T>() or FormBuilder.fromConfig().

type LoginForm = {
email: string
password: string
}

const builder = FormBuilder.create<LoginForm>()
.addFields([
{ name: 'email', type: 'email', label: 'Email' },
{ name: 'password', type: 'password', label: 'Password' },
])
.setInitialValues({ email: '', password: '' })
.setValidationSchema(
yup.object({
email: yup.string().email().required(),
password: yup.string().min(8).required(),
}),
)
.onSubmit(async (values) => {
await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(values),
})
})

Useful builder methods:

  • addField(field)
  • addFields(fields)
  • addFieldGroup(prefix, group)
  • setInitialValues(values)
  • setValidationSchema(schema)
  • setLayout(layout)
  • setButtons(buttons)
  • onSubmit(handler)
  • onReset(handler)
  • onChange(handler)
  • setValidationBehavior({ validateOnChange, validateOnBlur, validateOnMount })
  • use(middleware)

Runtime methods:

  • setFieldValue(name, value)
  • setFieldTouched(name, touched?)
  • validate()
  • validateField(name, value?)
  • submit()
  • reset(values?)
  • fillWithFakeData() — dev-only, see below

Async-select and async-validation methods are also part of the public API, including:

  • loadFieldOptions(fieldName, searchTerm?, force?)
  • validateFieldAsync(name, value?)
  • cancelAsyncValidation(name)

Dev tools

fillWithFakeData() fills every field with a plausible placeholder value, useful for skipping manual data entry while building a form. It's disabled by default and must be opted into via FormBuilderOptions:

const builder = FormBuilder.create<LoginForm>({
devTools: { fakeData: true },
}).addFields([
{ name: 'email', type: 'email', label: 'Email' },
{ name: 'password', type: 'password', label: 'Password' },
])

builder.fillWithFakeData()

Calling it without the flag enabled logs a warning and does nothing. Values are generated per field type (e.g. a random option for select/radio, a number within min/max, true for checkbox/switch); asyncSelect, file, custom, and dateRange fields are skipped since there's no generic value to fabricate for them. Only enable this flag in development.

Field types

Supported type values:

text, email, password, number, textarea, select, asyncSelect, combobox, checkbox, switch, radio, date, dateRange, time, file, array, custom

React hook

export function LoginFormView() {
const form = useFormBuilder({ builder })

return (
<form
onSubmit={(event) => {
event.preventDefault()
void form.submit()
}}
>
<input
value={form.values.email}
onChange={(event) => void form.setFieldValue('email', event.target.value)}
onBlur={() => form.setFieldTouched('email', true)}
/>
<input
value={form.values.password}
onChange={(event) => void form.setFieldValue('password', event.target.value)}
onBlur={() => form.setFieldTouched('password', true)}
/>
<button type="submit" disabled={form.isSubmitting}>
Sign in
</button>
</form>
)
}

useFormBuilder({ builder }) returns:

  • values
  • errors
  • touched
  • currentStep
  • totalSteps
  • isSubmitting
  • isValid
  • setFieldValue
  • setFieldTouched
  • validate
  • submit
  • reset
  • nextStep
  • prevStep

nextStep and prevStep are placeholders on the plain hook. Actual multi-step orchestration lives in MultiStepFormBuilder.

MultiStepFormBuilder

type SignupForm = {
email: string
password: string
firstName: string
lastName: string
}

const wizard = MultiStepFormBuilder.create<SignupForm>()
.addSteps([
{
id: 'account',
title: 'Account',
fields: [
{ name: 'email', type: 'email', label: 'Email' },
{ name: 'password', type: 'password', label: 'Password' },
],
},
{
id: 'profile',
title: 'Profile',
fields: [
{ name: 'firstName', type: 'text', label: 'First name' },
{ name: 'lastName', type: 'text', label: 'Last name' },
],
},
])
.setInitialValues({
email: '',
password: '',
firstName: '',
lastName: '',
})

Public multi-step methods:

  • nextStep()
  • previousStep()
  • goToStep(stepIdOrIndex)
  • validateCurrentStep()
  • validateStep(stepId)
  • validateAllSteps()
  • submit()
  • reset(values?)