Skip to content

useMutationForm

Turns a mutation marked with @endpoint into a progressively enhanced form: it submits natively before JavaScript loads, then runs the mutation client-side once hydrated. See Forms for the full guide.

import { graphql, useMutationForm } from '$houdini'
export function NewUser() {
const { Form, state, pending } = useMutationForm(graphql(`
mutation CreateUser($name: String!)
@endpoint(redirect: "/users/{ createUser.id }") {
createUser(name: $name) {
id
}
}
`))
return (
<Form>
<input name="name" required />
{state?.errors && <p role="alert">{state.errors[0].message}</p>}
<button disabled={pending}>Create user</button>
</Form>
)
}

Signature

function useMutationForm(document, opts?): MutationForm

The second argument is optional:

OptionTypeDescription
idstringDistinguishes multiple forms for the same mutation on one page, and keys the server-injected result. Defaults to the @endpoint(id:) or the mutation name.
onSuccess(data) => voidEnhanced-path-only side effect after a successful submit (no-op without JS).
onError(errors) => voidEnhanced-path-only side effect after a failed submit (no-op without JS).

Returns

FieldTypeDescription
FormcomponentThe recommended way to render: a <form> with the markers injected and pending published to useMutationFormStatus. Forwards any <form> props.
state{ data, errors } | nullThe submit result; null before the first submit. Same shape on both paths.
pendingbooleanTrue while a submit is in flight (enhanced path).
formobjectEscape hatch for spreading onto your own <form>: action, method, onSubmit, and encType when the mutation takes an Upload. No status context.
hiddenReactNodeEscape-hatch companion to form — the marker fields the no-JS POST needs; render inside the form.

useMutationFormStatus

Reads the pending state of the nearest <Form> from any child component, without prop drilling. Shaped like React’s useFormStatus, but it can see Houdini’s forms.

import { useMutationFormStatus } from '$houdini'
function Submit() {
const { pending } = useMutationFormStatus()
return <button disabled={pending}>{pending ? 'Saving…' : 'Create'}</button>
}

Only works inside the Form component returned by useMutationForm (a plain {...form} spread provides no context); use the pending returned by the hook otherwise.