inertia-vue-development

star 3

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.

Barbapapazes By Barbapapazes schedule Updated 2/28/2026

name: inertia-vue-development description: "Develops Inertia.js v2 Vue client-side applications. Activates when creating Vue pages, forms, or navigation; using ,
, 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

<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'

function handleClick() {
  router.visit('/users')
}

// Or with options
function createUser() {
  router.visit('/users', {
    method: 'post',
    data: { name: 'John' },
    onSuccess: () => console.log('Done'),
  })
}
</script>

<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 v-slot="{ errors, processing, wasSuccessful }" action="/users" method="post">
    <input type="text" name="name">
    <div v-if="errors.name">
      {{ errors.name }}
    </div>

    <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>
</template>

Form Component With All Props

<script setup>
import { Form } from '@inertiajs/vue3'
</script>

<template>
  <Form
    v-slot="{
      errors,
      hasErrors,
      processing,
      progress,
      wasSuccessful,
      recentlySuccessful,
      setError,
      clearErrors,
      resetAndClearErrors,
      defaults,
      isDirty,
      reset,
      submit,
    }"
    action="/users"
    method="post"
  >
    <input type="text" name="name" :value="defaults.name">
    <div v-if="errors.name">
      {{ errors.name }}
    </div>

    <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>
</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
    v-slot="{ errors, processing, wasSuccessful }"
    action="/users"
    method="post"
    reset-on-success
    set-defaults-on-success
  >
    <input type="text" name="name">
    <div v-if="errors.name">
      {{ errors.name }}
    </div>

    <button type="submit" :disabled="processing">
      Submit
    </button>
  </Form>
</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'

const form = useForm({
  name: '',
  email: '',
  password: '',
})

function submit() {
  form.post('/users', {
    onSuccess: () => form.reset('password'),
  })
}
</script>

<template>
  <form @submit.prevent="submit">
    <input v-model="form.name" type="text">
    <div v-if="form.errors.name">
      {{ form.errors.name }}
    </div>

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

    <input v-model="form.password" type="password">
    <div v-if="form.errors.password">
      {{ form.errors.password }}
    </div>

    <button type="submit" :disabled="form.processing">
      Create User
    </button>
  </form>
</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 class="h-4 bg-gray-200 rounded w-1/2" />
    </div>
    <ul v-else>
      <li v-for="user in users" :key="user.id">
        {{ user.name }}
      </li>
    </ul>
  </div>
</template>

Polling

Automatically refresh data at intervals:

<script setup>
import { router } from '@inertiajs/vue3'
import { onMounted, onUnmounted } from 'vue'

defineProps({
  stats: Object
})

let interval

onMounted(() => {
  interval = setInterval(() => {
    router.reload({ only: ['stats'] })
  }, 5000) // Poll every 5 seconds
})

onUnmounted(() => {
  clearInterval(interval)
})
</script>

<template>
  <div>
    <h1>Dashboard</h1>
    <div>Active Users: {{ stats.activeUsers }}</div>
  </div>
</template>

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'

defineProps({
  stats: Object
})
</script>

<template>
  <div>
    <h1>Dashboard</h1>

    <!-- stats prop is loaded only when this section scrolls into view -->
    <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>
</template>

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 version
Install via CLI
npx skills add https://github.com/Barbapapazes/hackathon-paris --skill inertia-vue-development
Repository Details
star Stars 3
call_split Forks 2
navigation Branch main
article Path SKILL.md
More from Creator
Barbapapazes
Barbapapazes Explore all skills →