TypeScript
Import the root types on this page from form-please.
import type { FieldPath, FormInput, FormOutput } from "form-please"This page covers every type exported from each entry point. A section for a
subpath entry names its import path, for example form-please/history.
Import the types in that section from that path.
For functions, components, options, and runtime behavior, read the API reference.
Choose the type you need
Start with these types in application code:
| Task | Type |
|---|---|
Type form state and defaultValues. | FormInput<Schema> |
| Type a successful submit result. | FormOutput<Schema> |
| Accept a valid field name. | FieldPath<Value> |
| Type a reusable form fragment. | FormFragment<Schema, Controls, ...> |
| Type a custom control component. | ControlProps<Value, OwnProps, Context, Option> |
| Type form-local value middleware. | FormMiddleware<Input, Context> |
Most calls to defineForm, useForm, and createFormKit infer the remaining
types. Add an explicit type when you export reusable configuration or build a
library integration.
Schema input and output
StandardSchema<Input, Output> is the common schema contract. Form, Please
works with any library that implements this contract.
FormInput<Schema> is the schema input type that React Hook Form (RHF) stores.
FormOutput<Schema> is the parsed value passed to onSubmit. These types can
be different when the schema transforms data.
type ProfileInput = FormInput<typeof profileSchema>
// { name: string; age: string; contacts: { email: string }[] }
type ProfileOutput = FormOutput<typeof profileSchema>
// { name: string; age: number; contacts: { email: string }[] }
const defaultValues = {
name: "Ada Lovelace",
age: "36",
contacts: [{ email: "ada@example.com" }],
} satisfies ProfileInputUse the input type for defaultValues, field paths, controls, and resolvers.
Use the output type after successful submission. Do not use the output type to
describe form state.
| Type | Purpose |
|---|---|
StandardSchema<Input, Output> | Describes a Standard Schema validator. Output defaults to Input. |
FormInput<Schema> | Extracts the schema input type. |
FormOutput<Schema> | Extracts the schema output type. |
DeepReadonly<Value> | Recursively models a readonly value. Functions, dates, files, and React elements keep their types. It does not freeze data at runtime. |
Field paths
Path types use the schema input shape and React Hook Form path syntax. Array
indexes use dot segments, such as contacts.0.email.
const contactEmailPath = "contacts.0.email" satisfies FieldPath<ProfileInput>
const contactsPath = "contacts" satisfies ArrayFieldPath<ProfileInput>
type ContactEmail = PathValue<ProfileInput, "contacts.0.email">
// string
type FieldUpdate<Value, Path extends FieldPath<Value>> = {
readonly path: Path
readonly value: PathValue<Value, Path>
}
const emailUpdate = {
path: "contacts.0.email",
value: "grace@example.com",
} satisfies FieldUpdate<ProfileInput, "contacts.0.email">| Type | Result |
|---|---|
FieldPath<Value> | All valid string paths in Value. |
PathValue<Value, Path> | The value at one valid path. |
ArrayFieldPath<Value> | RHF object-array paths that cannot be null or undefined. |
Use FieldPath when a component or helper accepts any field. Add a second path
generic when its value type must stay linked to the selected path. The
FieldUpdate type in the example keeps this relationship.
Definition and UI types
kit.defineForm() accepts a UI tree plus an optional managed-update policy and
returns a normalized FormDefinition. Let the call infer the type for a
definition that stays in one file.
The factory builder types each node from the schema and kit. The tree needs no type annotation:
const profileDefinition = profileKit.defineForm(profileSchema, (ui) => [
ui.field("name", {
control: "text",
label: "Name",
readOnly: (_values, { context }) => !context.canEdit,
}),
ui.array("contacts", {
label: "Contacts",
itemDefault: { email: "" },
children: (contact) => [
contact.field("email", { control: "text", label: "Email" }),
],
}),
])The node types below carry the schema input, control registry, context, slot
configuration, selectable options, and grid values through the complete tree.
Use defineFragment instead of a separate node list to share UI.
| Type | Purpose |
|---|---|
UiNode<Input, Controls, ...> | Union of ordinary field, section, array, and render source nodes. |
FieldNode<Input, Controls, ...> | Field node with compatible paths, controls, props, and selectable options. |
SectionNode<Input, Controls, ...> | Section node with typed child nodes. |
ArrayNode<Input, Controls, ...> | Array node for one non-nullable object-array path. |
RenderNode<Input, Context> | React component node with resolved interaction state. |
FormFragment<Schema, Controls, ...> | Schema-owned UI fragment created by defineFragment. |
FormDefinition<Schema, Controls, ...> is the normalized, readonly result of
defineForm. It contains the schema, grid, and normalized nodes. Do not create
this object manually. Its generic parameters preserve the kit contracts.
Resolver types
A resolvable UI property accepts a static value or a synchronous resolver.
Ordinary form resolvers receive the complete schema input and { context }.
Fragment-authored resolvers receive the local fragment input instead.
type Visibility = UiResolver<boolean, ProfileInput, ProfileContext>
const canShowProfile: Visibility = (values, { context }) =>
context.canEdit && values.name.length > 0| Type | Purpose |
|---|---|
UiResolver<Result, Input, Context> | Synchronous function that returns a derived UI value. |
UiResolverValues<Input> | Deeply readonly resolver values. |
UiResolverDetails<Context> | Object that contains deeply readonly context. |
Resolvable<Value, Input, Context> | Static Value or a UiResolver that returns it. |
ErrorDisplay | "all" or "first" for the errorDisplay option of a kit, form, field, or array. |
WhenHidden<Value> | "keep", "reset", or { value } for the field whenHidden property. |
ReactUiContent | A React element or string accepted by UI content properties. |
Resolvable excludes a static function when Value is callable. This rule
prevents Form, Please from confusing a component with a resolver.
DefaultGridValue is the default grid union: 1 | 2 | 3 | 4. A custom kit
infers its grid union from createFormKit({ grid }).
Render-node types
RenderNodeComponent is a React component that receives
RenderNodeProps. The props contain only disabled and readOnly. Use
RenderNode<Input, Context> to type the complete node.
Control types
defineControl<Value, OwnProps, Context, Option>() returns a typed
ControlDefinition. The value type controls which schema fields can use the
control. The context type controls which form kits can use it.
function MoneyControl({
value,
setValue,
blur,
input,
meta,
props: moneyProps,
context,
disabled,
readOnly,
required,
}: ControlProps<number | undefined, MoneyProps, MoneyContext>) {
return (
<>
<input
aria-describedby={input["aria-describedby"]}
aria-invalid={meta.invalid || undefined}
disabled={disabled}
id={input.id}
lang={context.locale}
min={moneyProps.min}
name={input.name}
onBlur={blur}
onChange={(event) => {
const nextValue = event.currentTarget.valueAsNumber
if (Number.isNaN(nextValue)) {
setValue(undefined)
return
}
setValue(nextValue)
}}
readOnly={readOnly}
ref={input.ref}
required={required}
type="number"
value={value ?? ""}
/>
<span aria-hidden="true">{moneyProps.currencyLabel}</span>
</>
)
}
const moneyInput = {
component: MoneyControl,
} satisfies DefineControlInput<
number | undefined,
MoneyProps,
MoneyContext,
never
>
const money = defineControl<number | undefined, MoneyProps, MoneyContext>(
moneyInput,
)
type MoneyValue = ControlValueOf<typeof money> // number | undefined
type MoneyControlOwnProps = ControlOwnPropsOf<typeof money> // MoneyProps
type RequiredContext = ControlContextOf<typeof money> // MoneyContext| Type | Purpose |
|---|---|
ControlProps<Value, OwnProps, Context, Option> | Props passed to a custom control component. |
ControlDefinition<Value, OwnProps, Context, Option> | Typed control returned by defineControl. |
DefineControlInput<Value, OwnProps, Context, Option> | Input object accepted by defineControl. |
OptionValue<Value> | Marks a control option value for narrowing to the selected schema input path. |
FieldOptionsSource<Option, Input, Context> | Static options or a tracked options function. |
FieldOptionsResolver<Option, Input, Context> | Function that returns options synchronously or asynchronously. |
FieldOptionsResolverDetails<Input, Context> | Readonly values, context, and cancellation signal. |
ControlDefinitionRegistry | Readonly record of named control definitions. |
AnyControlDefinition | Non-specific control type used in registries. |
Put OptionValue<Value> on the scalar option or on one property of a structured
option. A field definition replaces the marker with the compatible schema input
union at its path. The control receives OwnProps through props and the
resolved collection through options.
See Option controls for a custom control and Option values for definition-side inference.
The extraction types read the hidden contract from a control definition:
| Type | Extracts |
|---|---|
ControlValueOf<Control> | Field value type. |
ControlOwnPropsOf<Control> | Definition-node props type. |
ControlOptionOf<Control> | One selectable option item. |
ControlContextOf<Control> | Required form context type. |
Use these extraction types for wrappers and integration tests. Application forms usually rely on inference.
Form-kit and binding types
A form kit is the reusable design-system contract. A form binding is one component-local form instance.
const formOptions = {
defaultValues,
context: { canEdit: true },
onSubmit: ({ input, value }) => {
input.age.toUpperCase() // string
value.age.toFixed(0) // number
},
} satisfies UseFormOptions<typeof profileSchema, ProfileContext>
function ProfileForm() {
const form: FormBinding<typeof profileSchema, ProfileContext> =
profileKit.useForm(profileDefinition, formOptions)
return (
<profileKit.AutoForm aria-label="Profile" form={form}>
<profileKit.Submit>Save profile</profileKit.Submit>
</profileKit.AutoForm>
)
}| Type | Purpose |
|---|---|
FormKit<Controls, ...> | Kit methods, components, controls, slots, grid, and context contract. |
CreateFormKitOptions<Controls, ...> | Options accepted by createFormKit. |
DefineFormOptions<Schema, Context> | Definition-owned beforeUpdate, ordered middleware, and afterUpdate. |
FormDefinitionUpdatePolicy<Schema, Context> | Normalized readonly managed-update policy stored by a definition. |
UseFormOptions<Schema, Context> | defaultValues, context, flags, validation modes, and submit handler. |
FormSubmitDetails<Schema, Context> | Parsed output, schema input, form binding, and submitter snapshot passed to a submit handler. |
FormActionConfig<Schema, Context> | One submit action: implicit, validate, and onSubmit. |
FormActionsConfig<Schema, Context> | The actions record accepted by useForm. |
FormActionValidateDetails<Schema> | Parsed output and schema input passed to an action validate. |
FormAction<Schema, Context, Name> | A bound action from form.actions. |
FormSubmission<Name> | External store of the running action and the last onSubmit rejection. |
FormSubmissionSnapshot<Name> | { action, error } snapshot of FormSubmission. error is { value } or null. |
FormIssueInput<Schema> | An issue with a typed optional path for validate and setIssues. |
SetIssuesOptions<Schema> | The focus option of setIssues. |
FormBinding<Schema, Context> | Raw RHF API, managed update, fixed definition, and current context. |
FormProps<Schema, Context> | Props for kit.Form. |
AutoFormProps<Schema, Context> is currently the same contract as
FormProps. It is a separate public name for components that wrap
kit.AutoForm.
Use form.api from FormBinding for unchanged React Hook Form operations. Use
form.update for a managed value transaction. The other public fields are the
fixed definition and current context. Read FormBinding on the API
page for their behavior.
Managed value types
Use these types when you configure value middleware or create a reusable managed update:
| Type | Purpose |
|---|---|
FormUpdateRecipe<Input> | Synchronous Immer recipe accepted by form.update and middleware api.update. |
FormMiddleware<Input, Context> | Redux-shaped middleware for one form binding. |
FormMiddlewareApi<Input> | Read current values or start a later managed update. |
FormMiddlewareNext | Forward authoritative patches to the next middleware or terminal. |
ValueTransaction<Input, Context> | TypeScript-readonly proposal or final committed update with previous values, next values, patches, source, and context. It is not a frozen snapshot. |
ValueTransactionSource<Input> | Discriminated source for a control, array action, form.update, or optional feature restore. |
ValuePatch | Readonly Immer operation with a segment-array path. |
Middleware can replace the terminal return value. Therefore, form.update and
FormMiddlewareNext return unknown. Read Value middleware for
runtime rules and examples.
Managed value history types
Import history types from form-please/history:
| Type | Purpose |
|---|---|
CreateHistoryOptions | Configure retention and control grouping. |
HistoryFeature | Reusable middleware plus exact-form handle lookup. |
HistoryHandle<Input> | Navigate, subscribe, clear, export, and import one form's history. |
HistorySnapshot | Current canUndo, canRedo, index, and length. |
HistoryOperationResult | applied, unavailable, cancelled, or transformed. |
HistoryJournal<Input> | Version 1 in-memory input positions and current index. |
UseHistoryResult<Input> | The useHistory return value: a HistoryHandle<Input> plus the current snapshot. |
Read Managed value history for the complete runtime contract.
Form persistence types
Import persistence types from form-please/persistence:
| Type | Purpose |
|---|---|
JsonValue | Value accepted by an adapter across its JSON boundary. |
PersistenceCodec<Value> | Tagged conversion for one explicit opaque value type. |
PersistenceMigration | Convert decoded input between application versions. |
FormPersistenceAdapter | Keyed asynchronous load, save, and remove transport. |
CreatePersistenceOptions | Configure the adapter, key, version, save delay, codecs, migration, and error observer. |
PersistenceErrorDetails | Identifies the failed restore, save, or clear operation. |
PersistenceFeature | Reusable middleware plus exact-form handle lookup. |
PersistenceHandle | Restore, start, flush, clear, and observe one form's draft. |
PersistenceSnapshot | Current restore phase and save state. |
PersistenceRestoreResult | applied, empty, cancelled, transformed, or conflict. |
UsePersistenceResult | The usePersistence return value: a PersistenceHandle plus the current snapshot. |
Read Form persistence for the complete runtime contract.
Devtools types
Import the devtools type from form-please/devtools:
| Type | Purpose |
|---|---|
FormPleaseDevtoolsProps<Schema, Context> | Props for FormPleaseDevtools: the form binding to inspect and an optional name label. |
Read Devtools for the runtime behavior.
Definition testing types
Import definition testing types from form-please/testing:
| Type | Purpose |
|---|---|
DefinitionTester<Definition> | Stateful selectors and production-backed definition operations. |
DefinitionTesterOptions<Definition> | Initial values, context, and interaction flags. |
DefinitionInspection<Definition> | Readonly values and stable public node projections for one resolution. |
DefinitionTransition<Definition> | Before, after, and exact public node changes. |
ManagedDefinitionTransition<Definition> | A definition transition plus commit status, final transaction, and middleware result. |
DefinitionNodeSnapshot<Definition> | Discriminated field, section, array, or render projection. |
DefinitionChange<Definition> | Added, removed, or property-level changed node. |
DefinitionTestValues<Definition> | Schema input inferred from the definition schema. |
DefinitionTestContext<Definition> | Runtime context inferred from the definition's kit. |
DefinitionFieldSnapshot, DefinitionSectionSnapshot,
DefinitionArraySnapshot, DefinitionRenderSnapshot,
DefinitionPropertyChange, DefinitionTestOption, and
DefinitionTesterRerenderOptions provide the narrower public contracts. Read
Test definitions for runtime behavior.
Slot and structure types
FormKitSlots<FieldOptions, SectionOptions, ArrayOptions> describes the six
required slot components. The three option generics set the corresponding
slotOptions prop types.
function ErrorMessage({ rootProps, issue }: ErrorMessageSlotProps) {
return (
<p {...rootProps} role="alert">
{issue.path !== undefined && `${issue.path}: `}
{issue.message}
</p>
)
}
const controls = createNativeControls()
const slots = {
...createDefaultSlots(),
ErrorMessage,
} satisfies FormKitSlots
const kitOptions = {
controls,
slots,
grid: [1, 2, 4],
} satisfies CreateFormKitOptions<typeof controls>
const customKit = createFormKit(kitOptions)
const formStyle = {
"--fp-row-gap": "1rem",
} satisfies FormPleaseStyle| Slot props type | Used by |
|---|---|
FieldSlotProps<Options> | Field slot. |
SectionSlotProps<Options> | Section slot. |
ArraySlotProps<Options> | Array slot. |
ArrayItemSlotProps | ArrayItem slot. |
ErrorMessageSlotProps | ErrorMessage slot. |
SubmitSlotProps<Schema> types the Submit slot and typed render functions. It
provides buttonProps, deeply readonly input values, isSubmitting,
isDirty, and canSubmit (!isValidating && !isSubmitting).
Shared structure types
| Type | Purpose |
|---|---|
StructuralRootProps | Generated attributes, style, and ref for a structural root element. |
StructuralNodeName | Allowed data-fp-node values for generated structure. |
FormPleaseStyle | React CSS properties plus the supported --fp-* variables. |
FormIssue | Normalized validation issue with message and optional path. |
Spread rootProps on the slot's root element. Do not replace its generated
attributes or ref. Read Form kits for every slot prop.
Control and preset types
The control and preset entries export these helper types. Read the matching API sections for the factories and the control props types.
Native control types
Import native control types from form-please/native-controls:
| Type | Purpose |
|---|---|
NativeSelectOption<Value> | One select or radio option with a value, a text label, and an optional disabled flag. |
NativeSelectEmptyOption | The props.emptyOption entry that maps an empty HTML value to undefined. |
NativeTextType | The HTML input types of the text control: text, email, password, search, tel, and url. |
Read Native controls for the props type of each control.
Default slot types
Import default slot types from form-please/default-slots:
| Type | Purpose |
|---|---|
DefaultSlotsI18n | The array action messages. Read Localization for the keys. |
DefaultSlotI18nValue<Data> | A fixed string, or a function that gets readonly Data and returns a string. |
DefaultArrayAddI18nData | The arrayAdd data: the optional label of the array node. |
DefaultArrayItemI18nData | The item action data: the zero-based index and the one-based position. |
Read Default slots for the i18n option.
Material UI preset types
Import Material UI preset types from form-please/preset-mui:
| Type | Purpose |
|---|---|
CreateMuiFormKitOptions | Options for createMuiFormKit: an optional partial i18n object. |
MuiFormKitI18n | The messages addItem, removeItem, moveItemUp, moveItemDown, and chooseFile. |
MuiSelectOption | One select or select-multiple option with a value, a label, and an optional disabled flag. |
MuiRadioOption | One radio option. It adds optional radioProps and labelProps to the select option fields. |
MuiAutocompleteTextFieldProps | The textFieldProps of the autocomplete and autocomplete-multiple controls. |
MuiFieldSlotOptions | Field slotOptions: sx for the FormControl root. |
MuiSectionSlotOptions | Section slotOptions: sx for the section root and layoutSx for its grid. |
MuiArraySlotOptions | Array slotOptions: sx for the array root and itemsSx for its item list. |
Read Material UI preset for the control names and their props types.
Resource state
ResourceState<Value, Error> is a readonly tagged union. Its status is
"pending", "success", or "error".
type Countries = ResourceState<readonly string[], Error>
function countryCount(resource: Countries) {
if (resource.status !== "success") return 0
return resource.value.length
}The type does not fetch or cache data. Use it to expose application-owned resource state. Read Resource state for mapping and adapter examples.
Array reconciliation
FormBinding.array infers its row type from an ArrayFieldPath. Its reconcile
method checks string or number keys, the key callback, and complete rows returned
by create. See Reconcile selected rows.