Forms

Submitting forms

While it's possible to make classic form submissions with Inertia, it's not recommended, as they cause full page reloads. Instead, it's better to intercept form submissions and then make the request using Inertia.

<template>
  <form @submit.prevent="submit">
    <label for="first_name">First name:</label>
    <input id="first_name" v-model="form.first_name" />
    <label for="last_name">Last name:</label>
    <input id="last_name" v-model="form.last_name" />
    <label for="email">Email:</label>
    <input id="email" v-model="form.email" />
    <button type="submit">Submit</button>
  </form>
</template>

<script>
import { reactive } from 'vue'
import { Inertia } from '@inertiajs/inertia'

export default {
  setup () {
    const form = reactive({
      first_name: null,
      last_name: null,
      email: null,
    })

    function submit() {
      Inertia.post('/users', form)
    }

    return { form, submit }
  },
}
</script>

Unlike a classic ajax submitted form, with Inertia you don't handle the post submission behaviour client-side. Rather, you do this server-side using a redirect. And, of course, there is nothing stopping you from redirecting right back to the page that you're on.

class UsersController extends Controller
{
    public function index()
    {
        return Inertia::render('Users/Index', [
          'users' => User::all(),
        ]);
    }

    public function store()
    {
        User::create(
            Request::validate([
                'first_name' => ['required', 'max:50'],
                'last_name' => ['required', 'max:50'],
                'email' => ['required', 'max:50', 'email'],
            ])
        );

        return Redirect::route('users.index');
    }
}

Server-side validation

Handling server-side validation errors in Inertia works a little different than a classic ajax-driven form, where you catch the validation errors from 422 responses and manually update the form's error state. That's because Inertia never receives 422 responses. Rather, Inertia operates much more like a standard full page form submission.

See the validation page for more information.

Form helper

Since working with forms is so common, Inertia comes with a form helper designed to help reduce the amount of boilerplate needed for typical forms. Here's how to use it:

<template>
  <form @submit.prevent="form.post('/login')">
    <!-- email -->
    <input type="text" v-model="form.email">
    <div v-if="form.errors.email">{{ form.errors.email }}</div>
    <!-- password -->
    <input type="password" v-model="form.password">
    <div v-if="form.errors.password">{{ form.errors.password }}</div>
    <!-- remember me -->
    <input type="checkbox" v-model="form.remember"> Remember Me
    <!-- submit -->
    <button type="submit" :disabled="form.processing">Login</button>
  </form>
</template>

<script>
import { useForm } from '@inertiajs/inertia-vue3'

export default {
  setup () {
    const form = useForm({
      email: null,
      password: null,
      remember: false,
    })

    return { form }
  },
}
</script>

To submit the form, use the get, post, put, patch and delete methods.

form.submit(method, url, options)
form.get(url, options)
form.post(url, options)
form.put(url, options)
form.patch(url, options)
form.delete(url, options)

The submit methods support all the regular visit options, such as preserveState, preserveScroll, and the event callbacks. This can be helpful for performing tasks on successful form submissions, such as resetting inputs.

form.post('/profile', {
  preserveScroll: true,
  onSuccess: () => form.reset('password'),
})

If you need to modify the form data before it's sent to the server, you can do this via the transform() method.

form
  .transform((data) => ({
    ...data,
    remember: data.remember ? 'on' : '',
  }))
  .post('/login')

You can use the processing property to track if a form is currently being submitted. This can be helpful for preventing double form submissions, by disabling the submit button.

<button type="submit" :disabled="form.processing">Submit</button>

In the event that you're uploading files, the current progress event is available via the progress property. This is helpful for showing upload progress. For example:

<progress v-if="form.progress" :value="form.progress.percentage" max="100">
  {{ form.progress.percentage }}%
</progress>

In the event there are form errors, they are available via the errors property.

<div v-if="form.errors.email">{{ form.errors.email }}</div>

To check if a form has any errors, use the hasErrors property. To clear form errors, use the clearErrors() method.

// Clear all errors
form.clearErrors()

// Clear errors for specific fields
form.clearErrors('field', 'anotherfield')

If you're using a client-side input validation libraries or do additional checks of your own, you can also set your own errors on the form by using the setErrors() method.

// Set a single error
form.setError('field', 'Your error message.');

// Set multiple errors at once
form.setError({
  foo: 'Your error message for the foo field.',
  bar: 'Some other error for the bar field.'
});
Unlike an actual form submission, the page's props remain unchanged when manually setting errors on a form instance.

When a form has been successfully submitted, the wasSuccessful property will be true. In addition to this, there is also a recentlySuccessful property, which will be set to true for two seconds after a successful form submission. This is helpful for showing temporary success messages.

To reset the form values back to their default values, you can use the reset() method.

// Reset the form
form.reset()

// Reset specific fields
form.reset('field', 'anotherfield')

If your form's default values become outdated, you can use the defaults() method to update them. This way, the next time the reset() method is used, the form will be reset to the correct values.

// Set the form's current values as the new defaults
form.defaults()

// Update the default value of a single field
form.defaults('email', 'updated-default@example.com')

// Update the default value of multiple fields
form.defaults({
  name: 'Updated Example',
  email: 'updated-default@example.com',
})

To cancel a form submission, use the cancel() method.

form.cancel()

To have form helper data and errors automatically remembered in history state, you can provide a unique form key as the first argument when instantiating your form.

import { useForm } from '@inertiajs/inertia-vue3'

const form = useForm('CreateUser', data)
const form = useForm(`EditUser:${user.id}`, data)

To check if a form has any changes, use the isDirty property.

<div v-if="form.isDirty">There are unsaved form changes.</div>

File uploads

When making visits that include files, Inertia will automatically convert the request data into a FormData object.

See the file uploads page for more information.

XHR/fetch submissions

Using Inertia to submit forms works great for the vast majority of situations. However, in the event that you need more fine-grain control over the form submission, there's nothing stopping you from making plain xhr or fetch requests instead. Using both approaches in the same application is totally fine!