Elderform
Form handling without tears and predictable form state based on defined parameters. Elderform gives you everything you need to create robust forms and stays out of your way.
Features
- Async validation
- Create reusable forms
- Predictable form state
- Cancel form submission
- Full typescript support
- Schemaless (define your fields as you like)
- Tiny: fully packed in just ~6kb
- Use any validation library or roll your own
- Framework agnostic
- Ships with sensible defaults for form handling
-
No more "how do I prevent multple submission while currently submitting"
Quick start
pnpm add xstate elderform
import * as z from 'zod';
import {createForm} from 'elderform';
const form = createForm({
initialValues: {
age: 10,
name: {
last: '',
first: '',
middle: '',
},
mother: {
name: {
last: '',
first: '',
middle: '',
},
},
},
onSubmit: () => {
return Promise.resolve();
},
});
form.spawn('name', null, v => zod.string().parse(v))
form.subscribe((state) => {
...
});
form.submit();
API
createForm(config)
-
config
(object) - config object from creating the form state machine (see below)
Config:
-
initialValues?
(object) - initial form values -
onSubmit(values: object)
- an async function that handles form submission
Returns:
An object which provides
-
submit
((...ignore?: string[]) => void) - a function to submit the form -
reset
- a function to reset the form state to its initial state -
cancel
(() => void) - function to cancel either the form validation or the current form submission -
submitAsync
- async version of submit and resolves with the submission result -
set
- ((name, value) => void) - a function to set the value for any given field -
subscribe
((stateListener) => () => void) - a state listener with the current state of the form (see below for stateListener) -
__service
- the base service (xstate interpreter), made available for library authors to creating wrappers for frameworks -
validate
((field, value?) => void) - function to validate given field
-
spawn
((name, value, validator) => void) - An escape hatch to spawn new fields not specified in the schema. (useful for creating dynamic forms) -
kill
((name) => void) - A function to kill aspawned
field
State Listener
subscribe(
currentState)
currentState
-
state - Form State
-
Boolean flags derived from form
state
valueisIdle
isValidating
isSubmitting
submitted
isError
-
isSuccess
- similar tosubmitted
-
Others
-
values
(object) - form values (Defaults to an empty object) -
data
(TData | null)- Defaults to
undefined
- The last data returned from successfully submission
- Defaults to
-
error
(TError | null)- Defaults to
undefined
- The error object last from submission, if an error was thrown
- Defaults to
-
errors
(Record<string, TErrors>) - an object of errors for each field after validation -
dataUpdatedAt
(number) - The timestamp for when the form most recently submitted successfully and returned data (Defaults to0
) -
errorUpdatedAt
(number) - The timestamp for when the form most recently failed to submit successfully and returned error (Defaults to0
).
-
Form State
-
idle
- when the form isn't actively performing any operation -
validating
- when the defined schema is being validated -
submitting
- when the is being submitted -
submitted
- if the form submitted successfully without any error -
error
- if the submission attempt resulted in an error. The error is contained in the corresponding error property
Field State
-
idle
- when the field is not performing any action -
validating
- when the field is validating -
success
- if the field was validated successfully -
failed
- if the field failed validation