Laravel Precognition for Vue with Inertia.js
Laravel Precognition Vue Inertia is an official frontend integration package designed to bring "live" validation capabilities to Vue 3 applications that utilize Inertia.js for server-driven UI. It enables developers to anticipate the outcome of future HTTP requests to a Laravel backend, primarily for providing real-time feedback on form inputs without requiring full page reloads. The current stable version of this package is `v2.0.0`, aligning with the core Laravel Precognition library's latest major release. Releases generally follow the development cadence of the broader Laravel ecosystem, with updates often introduced in sync with new Laravel framework versions or significant improvements to the core Precognition package. Its primary differentiator lies in its deep and seamless integration with Laravel's robust validation system and Inertia.js's simplified approach to building single-page applications, offering a highly streamlined developer experience for creating dynamic, interactive forms with instant server-side validation feedback.
Common errors
-
TypeError: useForm is not a function
cause `useForm` was imported incorrectly (e.g., as a default import or from a wrong path) or the package is not installed.fixEnsure `laravel-precognition-vue-inertia` is installed and `useForm` is imported as a named export: `import { useForm } from 'laravel-precognition-vue-inertia';`. -
Failed to load resource: the server responded with a status of 422 (Unprocessable Content) or Network Error
cause This typically indicates that the Laravel backend is not correctly configured for Precognition requests, or the CSRF token is missing/invalid.fixVerify your Laravel backend's `Kernel.php` has the `HandlePrecognition` middleware enabled for the web group. Also, ensure the CSRF token is included in your requests (Inertia handles this automatically, but check if custom requests are missing it). -
Property 'errors' does not exist on type 'PrecognitionForm<...>' or Property 'hasErrors' does not exist...
cause This TypeScript error often occurs when `PrecognitionForm` is used with incorrect generic types, or when the form's initial data structure doesn't match the expected type.fixEnsure the generic type passed to `useForm` (`useForm<MyFormType>`) accurately reflects the structure of your form data, including all possible fields and their types.
Warnings
- breaking Starting with `v2.0.0`, the package replaced the underlying HTTP client from Axios to the native `fetch` API. If you had custom Axios configurations or adapters, they will no longer be used.
- breaking In `v1.0.0`, the core `laravel-precognition` package removed its direct dependency on Inertia.js specific code, making `laravel-precognition-vue-inertia` the dedicated integration. While this package continues to provide Inertia support, ensure you are using the correct `laravel-precognition-vue-inertia` package for Inertia-based applications.
- gotcha TypeScript support for wildcard validation paths (e.g., `items.*.name`) was introduced in `v1.0.1` for the core package. If you are using an older version and relying on complex nested validation, TypeScript might not correctly infer types.
- gotcha Full support for Inertia 2.0 was added from `v0.5.14` of the underlying monorepo. If encountering issues with Inertia 2.0 features, ensure your `laravel-precognition-vue-inertia` version is up to date.
Install
-
npm install laravel-precognition-vue-inertia -
yarn add laravel-precognition-vue-inertia -
pnpm add laravel-precognition-vue-inertia
Imports
- useForm
import useForm from 'laravel-precognition-vue-inertia';
import { useForm } from 'laravel-precognition-vue-inertia'; - PrecognitionForm
import { PrecognitionForm } from 'laravel-precognition-vue-inertia';import type { PrecognitionForm } from 'laravel-precognition-vue-inertia'; - Form
import type { Form } from 'laravel-precognition-vue-inertia';
Quickstart
import { defineComponent } from 'vue';
import { useForm } from 'laravel-precognition-vue-inertia';
interface UserForm {
name: string;
email: string;
password?: string;
}
export default defineComponent({
setup() {
const form = useForm<UserForm>('post', '/users', {
name: '',
email: '',
password: '',
});
const submit = () => {
form.submit({
onSuccess: () => {
console.log('User created successfully, redirecting...');
form.reset();
// Example: Inertia.visit('/users');
},
onError: (errors) => {
console.error('Validation errors:', errors);
},
});
};
return {
form,
submit,
};
},
template: `
<form @submit.prevent="submit">
<div>
<label for="name">Name:</label>
<input
id="name"
type="text"
v-model="form.name"
@change="form.validate('name')"
/>
<div v-if="form.hasErrors('name')" style="color: red;">{{ form.errors.name }}</div>
</div>
<div>
<label for="email">Email:</label>
<input
id="email"
type="email"
v-model="form.email"
@change="form.validate('email')"
/>
<div v-if="form.hasErrors('email')" style="color: red;">{{ form.errors.email }}</div>
</div>
<div>
<label for="password">Password:</label>
<input
id="password"
type="password"
v-model="form.password"
@change="form.validate('password')"
/>
<div v-if="form.hasErrors('password')" style="color: red;">{{ form.errors.password }}</div>
</div>
<button type="submit" :disabled="form.processing || form.hasErrors()">
Create User
</button>
</form>
`
});