easy-forms
API reference

useFormRuntime

The hook that owns a form's store, dependency engine, and plugins.

import { useFormRuntime } from '@easy-forms/core';

Removed in 0.2

@easy-forms/core no longer exports a <Form> component. Core is headless: it ships this hook, and the chrome that used to live in <Form> is now the ejectable <EasyForm> you own. If you are upgrading, see Upgrading.

Signature

function useFormRuntime(
	schema: FormSchema<TFormData>,
	options?: UseFormRuntimeOptions
): { store: FormStore };

Options

PropTypeDefaultDescription
initialValuesRecord<string, unknown>Seed values for the internally created store. Ignored when you pass your own store.
storeFormStoreProvide an external store instead of creating one. An external store always wins.
dependencyHandlersDependencyHandlerRegistryAdditional or replacement handlers, merged over defaultDependencyHandlers.
pluginsFormPlugin[]Lifecycle plugins (logger, autosave, custom). Attached in their own effect.

What it owns

  • The store — created via createFormStore({ initialValues }), or the one you passed in.
  • The merged handler registry{ ...defaultDependencyHandlers, ...dependencyHandlers }.
  • The dependency engine — attached in an effect, detached on cleanup.
  • Plugins — attached in a second effect, skipped entirely when the array is empty.

It renders nothing. You provide the store yourself:

import { FormStoreProvider, RendererRegistryContext, useFormRuntime } from '@easy-forms/core';

function MyForm({ schema, onSubmit }) {
	const { store } = useFormRuntime(schema, { plugins: [] });

	return (
		<FormStoreProvider store={store}>
			<RendererRegistryContext.Provider value={myRegistry}>
				{/* your chrome + <Field>s */}
			</RendererRegistryContext.Provider>
		</FormStoreProvider>
	);
}

Mount order matters

The engine is attached inside useEffect. React runs child effects before parent effects, so by the time this hook's effect fires, every descendant <Field> has already registered with the store — and the engine's first pass sees all of them.

Call useFormRuntime from the component that owns the subtree — the one that renders the provider and the fields beneath it. Calling it from a component mounted beside the fields breaks that ordering and silently disables all dependencies.