,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ unknown extends TSubmitMeta ? TFormSubmitMeta : TSubmitMeta,
+ TComponents,
+ TFormComponents
+ >
+ fields: TFields
+ }
+ >,
+ ) => ComponentChildren {
+ return function Render(innerProps) {
+ const fieldGroupProps = useMemo(() => {
+ return {
+ form: innerProps.form,
+ fields: innerProps.fields,
+ defaultValues,
+ formComponents,
+ }
+ }, [innerProps.form, innerProps.fields])
+ const fieldGroupApi = useFieldGroup(fieldGroupProps as any)
+
+ return render({ ...props, ...innerProps, group: fieldGroupApi as any })
+ }
+ }
+
+ return {
+ useAppForm,
+ withForm,
+ withFieldGroup,
+ }
+}
diff --git a/packages/preact-form/src/index.ts b/packages/preact-form/src/index.ts
new file mode 100644
index 000000000..c3c812b1c
--- /dev/null
+++ b/packages/preact-form/src/index.ts
@@ -0,0 +1,9 @@
+export * from '@tanstack/form-core'
+
+export { useStore } from '@tanstack/preact-store'
+
+export * from './createFormHook'
+export * from './types'
+export * from './useField'
+export * from './useFieldGroup'
+export * from './useForm'
diff --git a/packages/preact-form/src/types.ts b/packages/preact-form/src/types.ts
new file mode 100644
index 000000000..5923501ac
--- /dev/null
+++ b/packages/preact-form/src/types.ts
@@ -0,0 +1,139 @@
+import type {
+ DeepKeys,
+ DeepValue,
+ FieldApiOptions,
+ FieldAsyncValidateOrFn,
+ FieldOptions,
+ FieldValidateOrFn,
+ FormAsyncValidateOrFn,
+ FormState,
+ FormValidateOrFn,
+} from '@tanstack/form-core'
+import type { ComponentChildren } from 'preact'
+
+interface FieldOptionsMode {
+ mode?: 'value' | 'array'
+}
+
+export type PropsWithChildren = P & {
+ children?: ComponentChildren
+}
+
+/**
+ * The field options.
+ */
+export interface UseFieldOptions<
+ TParentData,
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TSubmitMeta,
+> extends FieldApiOptions<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TSubmitMeta
+ >,
+ FieldOptionsMode {}
+
+export interface UseFieldOptionsBound<
+ TParentData,
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+> extends FieldOptions<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync
+ >,
+ FieldOptionsMode {}
+
+export type ServerFormState<
+ TFormData,
+ TOnServer extends undefined | FormAsyncValidateOrFn,
+> = Pick<
+ FormState<
+ TFormData,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ TOnServer
+ >,
+ 'values' | 'errors' | 'errorMap'
+>
diff --git a/packages/preact-form/src/useField.tsx b/packages/preact-form/src/useField.tsx
new file mode 100644
index 000000000..2be9fa261
--- /dev/null
+++ b/packages/preact-form/src/useField.tsx
@@ -0,0 +1,684 @@
+'use client'
+
+import { useMemo, useState } from 'preact/hooks'
+import { useStore } from '@tanstack/preact-store'
+import { FieldApi, functionalUpdate } from '@tanstack/form-core'
+import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
+import type {
+ DeepKeys,
+ DeepValue,
+ FieldAsyncValidateOrFn,
+ FieldValidateOrFn,
+ FieldValidators,
+ FormAsyncValidateOrFn,
+ FormValidateOrFn,
+} from '@tanstack/form-core'
+import type { ComponentChildren, FunctionComponent } from 'preact'
+import type { UseFieldOptions, UseFieldOptionsBound } from './types'
+
+interface ReactFieldApi<
+ TParentData,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TPatentSubmitMeta,
+> {
+ /**
+ * A pre-bound and type-safe sub-field component using this field as a root.
+ */
+ Field: FieldComponent<
+ TParentData,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+ >
+}
+
+/**
+ * A type representing a hook for using a field in a form with the given form data type.
+ *
+ * A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field.
+ */
+export type UseField<
+ TParentData,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TPatentSubmitMeta,
+> = <
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+>(
+ opts: UseFieldOptionsBound<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync
+ >,
+) => FieldApi<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+>
+
+/**
+ * A hook for managing a field in a form.
+ * @param opts An object with field options.
+ *
+ * @returns The `FieldApi` instance for the specified field.
+ */
+export function useField<
+ TParentData,
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TPatentSubmitMeta,
+>(
+ opts: UseFieldOptions<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+ >,
+) {
+ const [fieldApi] = useState(() => {
+ const api = new FieldApi({
+ ...opts,
+ form: opts.form,
+ name: opts.name,
+ })
+
+ const extendedApi: typeof api &
+ ReactFieldApi<
+ TParentData,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+ > = api as never
+
+ extendedApi.Field = Field as never
+
+ return extendedApi
+ })
+
+ useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])
+
+ /**
+ * fieldApi.update should not have any side effects. Think of it like a `useRef`
+ * that we need to keep updated every render with the most up-to-date information.
+ */
+ useIsomorphicLayoutEffect(() => {
+ fieldApi.update(opts)
+ })
+
+ useStore(
+ fieldApi.store,
+ opts.mode === 'array'
+ ? (state) => {
+ return [
+ state.meta,
+ Object.keys((state.value as unknown) ?? []).length,
+ ]
+ }
+ : undefined,
+ )
+
+ return fieldApi
+}
+
+/**
+ * @param children A render function that takes a field API instance and returns a React element.
+ */
+interface FieldComponentProps<
+ TParentData,
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TPatentSubmitMeta,
+ ExtendedApi = {},
+> extends UseFieldOptions<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+ > {
+ children: (
+ fieldApi: FieldApi<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+ > &
+ ExtendedApi,
+ ) => ComponentChildren
+}
+
+interface FieldComponentBoundProps<
+ TParentData,
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TPatentSubmitMeta,
+ ExtendedApi = {},
+> extends UseFieldOptionsBound<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync
+ > {
+ children: (
+ fieldApi: FieldApi<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TPatentSubmitMeta
+ > &
+ ExtendedApi,
+ ) => ComponentChildren
+}
+
+/**
+ * A type alias representing a field component for a specific form data type.
+ */
+export type FieldComponent<
+ in out TParentData,
+ in out TFormOnMount extends undefined | FormValidateOrFn,
+ in out TFormOnChange extends undefined | FormValidateOrFn,
+ in out TFormOnChangeAsync extends
+ | undefined
+ | FormAsyncValidateOrFn,
+ in out TFormOnBlur extends undefined | FormValidateOrFn,
+ in out TFormOnBlurAsync extends
+ | undefined
+ | FormAsyncValidateOrFn,
+ in out TFormOnSubmit extends undefined | FormValidateOrFn,
+ in out TFormOnSubmitAsync extends
+ | undefined
+ | FormAsyncValidateOrFn,
+ in out TFormOnDynamic extends undefined | FormValidateOrFn,
+ in out TFormOnDynamicAsync extends
+ | undefined
+ | FormAsyncValidateOrFn,
+ in out TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ in out TPatentSubmitMeta,
+ in out ExtendedApi = {},
+> = <
+ const TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn