Develops Inertia.js v2 Vue client-side applications. Activates when creating Vue pages, forms, or navigation; using <Link>, <Form>, useForm, or router; working with deferred props, prefetching, or polling; or when user mentions Vue with Inertia, Vue pages, Vue forms, or Vue navigation.
name inertia-vue-development description Develops Inertia.js v2 Vue client-side applications. Activates when creating Vue pages, forms, or navigation; using <Link>, <Form>, useForm, or router; working with deferred props, prefetching, or polling; or when user mentions Vue with Inertia, Vue pages, Vue forms, or Vue navigation. license MIT metadata {"author":"laravel"} Inertia Vue Development When to Apply Activate this skill when: Creating or modifying Vue page components for Inertia Working with forms in Vue (using
<Form> or useForm ) Implementing client-side navigation with <Link> or router Using v2 features: deferred props, prefetching, WhenVisible, InfiniteScroll, once props, flash data, or polling Building Vue-specific features with the Inertia protocol Documentation Use search-docs for detailed Inertia v2 Vue patterns and documentation. Basic Usage Page Components Location Vue page components should be placed in the resources/js/Pages directory. Page Component Structure Important: Vue components must have a single root element. <script setup> defineProps({ users: Array }) </script> <template> <div> <h1>Users</h1> <ul> <li v-for="user in users" :key="user.id"> {{ user.name }} </li> </ul> </div> </template> Client-Side Navigation Basic Link Component Use <Link> for client-side navigation instead of traditional <a> tags: <script setup> import { Link } from '@inertiajs/vue3' </script> <template> <div> <Link href="/">Home</Link> <Link href="/users">Users</Link> <Link :href="`/users/${user.id}`">View User</Link> </div> </template> Link with Method <script setup> import { Link } from '@inertiajs/vue3' </script> <template> <Link href="/logout" method="post" as="button"> Logout </Link> </template> Prefetching Prefetch pages to improve perceived performance: <script setup> import { Link } from '@inertiajs/vue3' </script> <template> <Link href="/users" prefetch> Users </Link> </template> Programmatic Navigation <script setup> import { router } from '@inertiajs/vue3' <template> <Link href="/users">Users</Link> <Link href="/logout" method="post" as="button">Logout</Link> </template> Form Handling Form Component (Recommended) The recommended way to build forms is with the <Form> component: <script setup> import { Form } from '@inertiajs/vue3' </script> <template> <Form action="/users" method="post" #default="{ errors, processing, wasSuccessful }"> <input type="text" name="name" /> <div v-if="errors.name">{{ errors.name }}</div> </template> Form Component With All Props <script setup> import { Form } from '@inertiajs/vue3' </script> <template> <Form action="/users" method="post" #default="{ errors, hasErrors, processing, progress, wasSuccessful, recentlySuccessful, setError, clearErrors, resetAndClearErrors, defaults, isDirty, reset, submit }" > <input type="text" name="name" :value="defaults.name" /> <div v-if="errors.name">{{ errors.name }}</div> </template> Form Component Reset Props The <Form> component supports automatic resetting: resetOnError - Reset form data when the request fails resetOnSuccess - Reset form data when the request succeeds setDefaultsOnSuccess - Update default values on success Use the search-docs tool with a query of form component resetting for detailed guidance. <script setup> import { Form } from '@inertiajs/vue3' </script> <template> <Form action="/users" method="post" reset-on-success set-defaults-on-success #default="{ errors, processing, wasSuccessful }" > <input type="text" name="name" /> <div v-if="errors.name">{{ errors.name }}</div> </template> Forms can also be built using the useForm composable for more programmatic control. Use the search-docs tool with a query of useForm helper for guidance. useForm Composable For more programmatic control or to follow existing conventions, use the useForm composable: <script setup> import { useForm } from '@inertiajs/vue3' <template> <form @submit.prevent="submit"> <input type="text" v-model="form.name" /> <div v-if="form.errors.name">{{ form.errors.name }}</div> </template> Inertia v2 Features Deferred Props Use deferred props to load data after initial page render: <script setup> defineProps({ users: Array }) </script> <template> <div> <h1>Users</h1> <div v-if="!users" class="animate-pulse"> <div class="h-4 bg-gray-200 rounded w-3/4 mb-2"></div> <div class="h-4 bg-gray-200 rounded w-1/2"></div> </div> <ul v-else> <li v-for="user in users" :key="user.id"> {{ user.name }} </li> </ul> </div> </template> Polling Use the usePoll composable to automatically refresh data at intervals. It handles cleanup on unmount and throttles polling when the tab is inactive. <script setup> import { usePoll } from '@inertiajs/vue3' <template> <div> <h1>Dashboard</h1> <div>Active Users: {{ stats.activeUsers }}</div> </div> </template> <script setup> import { usePoll } from '@inertiajs/vue3' <template> <div> <h1>Dashboard</h1> <div>Active Users: {{ stats.activeUsers }}</div> <button @click="start">Start Polling</button> <button @click="stop">Stop Polling</button> </div> </template> autoStart (default true ) — set to false to start polling manually via the returned start() function keepAlive (default false ) — set to true to prevent throttling when the browser tab is inactive WhenVisible Lazy-load a prop when an element scrolls into view. Useful for deferring expensive data that sits below the fold: <script setup> import { WhenVisible } from '@inertiajs/vue3' <template> <div> <h1>Dashboard</h1> </template> InfiniteScroll Automatically load additional pages of paginated data as users scroll: <script setup> import { InfiniteScroll } from '@inertiajs/vue3' <template> <InfiniteScroll data="users"> <div v-for="user in users.data" :key="user.id"> {{ user.name }} </div> </InfiniteScroll> </template> The server must use Inertia::scroll() to configure the paginated data. Use the search-docs tool with a query of infinite scroll for detailed guidance on buffers, manual loading, reverse mode, and custom trigger elements. Server-Side Patterns Server-side patterns (Inertia::render, props, middleware) are covered in inertia-laravel guidelines. Common Pitfalls Using traditional <a> links instead of Inertia's <Link> component (breaks SPA behavior) Forgetting that Vue components must have a single root element Forgetting to add loading states (skeleton screens) when using deferred props Not handling the undefined state of deferred props before data loads Using <form> without preventing default submission (use <Form> component or @submit.prevent ) Forgetting to check if <Form> component is available in your Inertia versionfunction handleClick() { router.visit('/users') }
// Or with options function createUser() { router.visit('/users', { method: 'post', data: { name: 'John' }, onSuccess: () => console.log('Done'), }) } </script>
<input type="email" name="email" />
<div v-if="errors.email">{{ errors.email }}</div>
<button type="submit" :disabled="processing">
{{ processing ? 'Creating...' : 'Create User' }}
</button>
<div v-if="wasSuccessful">User created!</div>
</Form>
<button type="submit" :disabled="processing">
{{ processing ? 'Saving...' : 'Save' }}
</button>
<progress v-if="progress" :value="progress.percentage" max="100">
{{ progress.percentage }}%
</progress>
<div v-if="wasSuccessful">Saved!</div>
</Form>
<button type="submit" :disabled="processing">
Submit
</button>
</Form>
const form = useForm({ name: '', email: '', password: '', })
function submit() { form.post('/users', { onSuccess: () => form.reset('password'), }) } </script>
<input type="email" v-model="form.email" />
<div v-if="form.errors.email">{{ form.errors.email }}</div>
<input type="password" v-model="form.password" />
<div v-if="form.errors.password">{{ form.errors.password }}</div>
<button type="submit" :disabled="form.processing">
Create User
</button>
</form>
defineProps({ stats: Object })
usePoll(5000) </script>
defineProps({ stats: Object })
const { start, stop } = usePoll(5000, { only: ['stats'], onStart() { console.log('Polling request started') }, onFinish() { console.log('Polling request finished') }, }, { autoStart: false, keepAlive: true, }) </script>
defineProps({ stats: Object }) </script>
<WhenVisible data="stats" :buffer="200">
<template #fallback>
<div class="animate-pulse">Loading stats...</div>
</template>
<template #default="{ fetching }">
<div>
<p>Total Users: {{ stats.total_users }}</p>
<p>Revenue: {{ stats.revenue }}</p>
<span v-if="fetching">Refreshing...</span>
</div>
</template>
</WhenVisible>
</div>
defineProps({ users: Object }) </script>