React
Install react as the peer and import the adapter from @ilokesto/form/react. useForm(form) returns the original form, useRegister, useField, useFieldState, useFormState, and handleSubmit. The returned use* helpers are React hooks, so call them inside components or custom hooks.
import { useForm } from '@ilokesto/form/react';
function ProfileForm({ form }) {
const { form: controller, useField, useRegister, useFormState } = useForm(form);
const name = useField({ name: ['profile', 'name'] });
const newsletter = useRegister({ name: 'newsletter', type: 'checkbox' });
const [role] = useRegister<HTMLSelectElement>([{ name: 'role' }]);
const state = useFormState();
return (
<form onSubmit={(event) => { event.preventDefault(); void controller.submit(save); }}>
<input {...name.props} />
<input type="checkbox" {...newsletter} />
<select {...role}><option value="user">User</option></select>
<button disabled={!state.isDirty || !state.isValid}>Save</button>
</form>
);
}Text inputs update through onChange; checkbox and radio fields use checked state; select and textarea bindings can be narrowed with a generic. Use useField when rendering errors or calling setValue, and useRegister when a plain input only needs props.
Syncing external values
ReactFormOptions accepts the current render values and plain resetOptions. The first defined value and each later value with a different Object.is identity call form.reset(values, resetOptions). undefined pauses synchronization without resetting, and passing the last defined object again remains a no-op. Changing only resetOptions is also a no-op; it is read only when a new values reference drives a reset.
const { form } = useForm({
defaultValues: emptyProfile,
values: query.data,
resetOptions: { keepDirtyValues: true },
});defaultValues creates the component-owned form once. The values effect ends when the component unmounts. useForm(existingForm) keeps its existing overload behavior and does not install external-value synchronization.
Cautions
Create the core form in a stable place, install the matching peer dependency, and import only from this adapter subpath in framework components. Keep server actions and domain helpers on the root @ilokesto/form API when they do not need rendering.