Cancel In-Flight Form Submissions in Inertia.js v3.7
Laravel Open Source #Inertia.js #Laravel #Vue #React #Svelte #Forms

Cancel In-Flight Form Submissions in Inertia.js v3.7

3 min read Mohamed Said Mohamed Said

Inertia.js v3.7.0 ships two targeted additions to the <Form> component that give you real control over in-flight submissions, plus a handful of quality-of-life improvements and bug fixes across all three adapters (Vue, React, Svelte).

cancelOnUnmount: Abort on Navigation or Modal Close

An in-flight upload does not stop just because the user closes the modal that started it. Navigation cancels requests as a side effect of the next sync request interrupting the previous one, but closing a modal interrupts nothing — the server still receives and processes the file.

The new cancelOnUnmount attribute fixes this:

<Form action="/avatar" method="post" cancel-on-unmount>
  <input type="file" name="avatar" />
  <button type="submit">Upload</button>
</Form>

When the form unmounts, the request is aborted. The attribute defaults to false, so existing forms keep their current behavior. Importantly, a submission that already succeeded is left alone — the cancel token becomes a no-op once the response has arrived, preventing a spurious onCancel event from firing after onSuccess.

Exposing cancel Through Slot Props, Ref, and Context

The <Form> component has always used useForm() internally, but never surfaced its cancel method. v3.7 changes that. cancel is now available through the slot props (Vue), render prop (React), component ref, and form context:

Vue

<Form action="/avatar" method="post" v-slot="{ processing, cancel }">
  <input type="file" name="avatar" />
  <button type="submit" :disabled="processing">Upload</button>
  <button v-if="processing" type="button" @click="cancel">Cancel</button>
</Form>

React

<Form action="/avatar" method="post">
  {({ processing, cancel }) => (
    <>
      <input type="file" name="avatar" />
      <button type="submit" disabled={processing}>Upload</button>
      {processing && (
        <button type="button" onClick={cancel}>Cancel</button>
      )}
    </>
  )}
</Form>

usePoll Now Returns a Reactive polling Value

Previously, usePoll returned only start and stop, forcing you to maintain your own boolean to track polling state. The hook now returns a reactive polling value:

import { usePoll } from '@inertiajs/vue3'
const { start, stop, polling } = usePoll(2000)
<template>
  <button v-if="polling" @click="stop">Pause updates</button>
  <button v-else @click="start">Resume updates</button>
</template>

polling reflects whether the poll is running, not whether a request is in flight. In Vue it is a Ref<boolean>, in React it is useState, and in Svelte it uses $state. Svelte users: keep the returned object and read poll.polling — destructuring loses reactivity.

Once Props Survive Instant Visits

Once props are resolved once and cached on the client. Instant visits swap in a placeholder page immediately while the real request runs in the background. Previously, the placeholder dropped both the once prop's value and its registry entry, causing the prop to come back empty. The router now copies remembered once props onto the placeholder page before the swap, unless the visit provides its own value for that prop.

Async Visits No Longer Cancelled by Navigation

Inertia's navigation cancellation was too broad — it cancelled all in-flight requests, including explicit async visits targeting other pages. Cancellation now matches on the request's origin and path, so only requests aimed at the page being navigated away from are cancelled. Deferred props, partial reloads, and polls still cancel as expected.

Bug Fixes

  • React back_forward restore: Tab duplication no longer leaves usePage() stuck on stale props.
  • replaceProp() identity: Path-aware immutable updates replace the previous deep clone, avoiding unnecessary re-renders of memoized components.
  • <Form> unmount crash: getFormData now returns an empty FormData when the form element is gone, preventing a TypeError from startTransition.

Upgrade

npm install @inertiajs/vue3@^3.7.0
# or @inertiajs/react, @inertiajs/svelte

Key Takeaways

  • Add cancel-on-unmount to any <Form> where an abandoned submission should not reach the server.
  • Use the cancel slot prop to render a cancel button on large uploads without any extra state.
  • Destructure polling from usePoll instead of tracking it yourself — but in Svelte, keep the full object.
  • Once props and instant visits now work correctly together.
  • Async visits to other pages survive navigation without being cancelled.

Source: Cancel In-Flight Form Submissions in Inertia.js v3.7 — Laravel News

Found this useful?

Frequently Asked Questions

3 questions
Q01 What does cancelOnUnmount do in Inertia.js v3.7?
When added to a `<Form>` component, `cancelOnUnmount` aborts the in-flight HTTP request as soon as the form unmounts — for example, when a modal is closed. It defaults to `false` so existing forms are unaffected, and it is a no-op if the response has already arrived.
Q02 How do I add a cancel button to an Inertia Form component?
In v3.7, `cancel` is exposed through the slot props (Vue), render prop (React), component ref, and form context. In Vue, use `v-slot="{ processing, cancel }"` and bind `cancel` to a button's click handler. In React, destructure it from the render prop function.
Q03 Why does usePoll in Svelte lose reactivity when destructured?
The Svelte adapter moved `usePoll` to a `.svelte.ts` file and backs the `polling` value with `$state`. Destructuring a `$state`-backed object breaks the reactive binding. Keep the full object returned by `usePoll` and read `poll.polling` to retain reactivity.

Continue reading

More Articles

View all