> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction à Vue.js — les bases pour l'utiliser avec Inertia × Laravel

> Nous présentons Vue.js, le framework JS le plus familier pour les utilisateurs de Laravel. De la présentation d'Options API / Composition API aux composants de pages, useForm et données partagées avec Inertia v3 × Vue 3, ce guide couvre les aspects pratiques.

## Qu'est-ce que Vue.js ?

Vue.js (ci-après Vue) est un framework JavaScript progressif pour construire des interfaces utilisateur. « Progressif » signifie que vous pouvez commencer petit et ajouter des fonctionnalités selon vos besoins ; il peut s'intégrer partiellement dans une page HTML existante ou servir à la construction de SPA à grande échelle.

L'essence de Vue est la **réactivité**. Lorsque les données changent, le DOM est automatiquement mis à jour ; le développeur n'a donc pas à gérer manuellement « quand et quels éléments mettre à jour ».

<Info>
  Cette page présente la combinaison Vue 3 et Inertia v3. Le starter kit de Laravel 13 utilise cette configuration par défaut.
</Info>

### Options API et Composition API

Vue 3 propose deux styles d'écriture de composants : **Options API** et **Composition API**.

**Options API** est le style traditionnel hérité de Vue 2. Vous définissez un composant avec un objet d'options : `data`, `methods`, `computed`, `mounted`, etc.

```vue theme={null}
<!-- Exemple avec Options API -->
<script>
export default {
    data() {
        return { count: 0 }
    },
    methods: {
        increment() {
            this.count++
        }
    }
}
</script>

<template>
    <button @click="increment">{{ count }}</button>
</template>
```

**Composition API** est le nouveau style introduit dans Vue 3. Combiné à la syntaxe `<script setup>`, il permet une écriture plus concise. Il offre également une meilleure réutilisation logique et une excellente affinité avec TypeScript.

```vue theme={null}
<!-- Exemple Composition API (<script setup>) -->
<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
    count.value++
}
</script>

<template>
    <button @click="increment">{{ count }}</button>
</template>
```

<Tip>
  Dans les starter kits Inertia × Laravel, le style Composition API avec `<script setup>` est le standard. Tous les exemples de cette page sont écrits en `<script setup>`.
</Tip>

***

## Position dans Laravel

### Histoire

La relation entre Vue et Laravel est ancienne, remontant à **Laravel 5.3 (2016)**, lorsque Vue a été adopté comme framework front-end par défaut. À l'époque, `package.json` incluait Vue, et un composant d'exemple `resources/js/components/ExampleComponent.vue` était fourni.

```mermaid theme={null}
timeline
    title Parcours de Laravel et Vue
    2016 : Laravel 5.3 — Vue adopté par défaut
    2019 : Laravel 6 — scaffold Vue séparé dans le paquet laravel/ui
    2021 : Laravel 8 — apparition du starter kit Jetstream + Inertia (Vue)
    2022 : Laravel 9 — passage à Vite
    2025 : Laravel 12 — refonte des starter kits (Vue / React)
    2026 : Laravel 13 — starter kit compatible Inertia v3
```

Dans **Laravel 6 (2019)**, le scaffold d'authentification a été extrait dans le paquet `laravel/ui`, et le scaffold Vue a également migré vers ce paquet. Aujourd'hui, le style principal consiste à choisir la configuration Inertia + Vue via un starter kit avec `laravel new`.

Pour les utilisateurs de Laravel, Vue est le framework JS le plus familier, et les ressources d'apprentissage en français sont abondantes.

### Le style principal actuel : Inertia × Vue

L'utilisation centrale de Vue dans Laravel aujourd'hui est **Inertia × Vue**. Inertia permet une architecture « monolithe moderne » où l'on peut passer directement des données du contrôleur Laravel aux composants Vue sans concevoir d'API.

```mermaid theme={null}
graph LR
    Browser["Navigateur"]
    Inertia["Inertia.js<br>(couche d'adaptateur)"]
    Laravel["Laravel<br>(contrôleurs)"]
    Vue["Vue<br>(composants de page)"]

    Browser <-->|XHR / rechargement complet| Inertia
    Inertia <-->|réponse Inertia| Laravel
    Inertia -->|props| Vue
    Vue -->|rendu| Browser
```

***

## Installation

### Via un starter kit (recommandé)

Pour démarrer un nouveau projet, utiliser un starter kit est le moyen le plus simple.

```shell theme={null}
laravel new my-app
```

En sélectionnant **Vue** dans l'invite interactive, tout ce qui suit est configuré automatiquement.

* `inertiajs/inertia-laravel` (adaptateur côté serveur)
* `@inertiajs/vue3` (adaptateur côté client)
* `vue` (Vue 3 lui-même)
* `@vitejs/plugin-vue` (plugin Vite)
* Middleware `HandleInertiaRequests`
* Écrans d'authentification (connexion, inscription, etc.) déjà implémentés en Inertia + Vue

### Installation manuelle

Pour ajouter à un projet existant, installez séparément les parties serveur et client.

```shell theme={null}
# Côté serveur (PHP)
composer require inertiajs/inertia-laravel

# Côté client (JavaScript)
npm install @inertiajs/vue3 vue
npm install --save-dev @vitejs/plugin-vue
```

Ensuite, ajoutez le plugin Vue à `vite.config.js`.

```js theme={null}
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
})
```

Démarrez l'application Inertia dans `resources/js/app.js`.

```js theme={null}
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'

createInertiaApp({
    resolve: (name) =>
        resolvePageComponent(
            `./pages/${name}.vue`,
            import.meta.glob('./pages/**/*.vue'),
        ),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .mount(el)
    },
})
```

<Info>
  Pour les détails de l'installation manuelle (configuration du template racine, enregistrement du middleware, etc.), consultez la [documentation officielle d'Inertia](https://inertiajs.com/installation).
</Info>

***

## Structure des répertoires

Dans les starter kits, les composants de page Vue sont placés dans le répertoire `resources/js/pages/`.

```
resources/js/
├── app.js             # Point de départ de l'application Inertia
├── bootstrap.js
├── components/        # Composants UI réutilisables
│   ├── NavBar.vue
│   └── ...
├── layouts/           # Composants de mise en page
│   ├── AppLayout.vue
│   └── AuthLayout.vue
└── pages/             # Composants de page Inertia (correspondant aux noms de contrôleurs)
    ├── Auth/
    │   ├── Login.vue
    │   └── Register.vue
    ├── Dashboard.vue
    └── Posts/
        ├── Index.vue
        ├── Create.vue
        └── Show.vue
```

Lorsque vous écrivez `Inertia::render('Posts/Index', [...])`, le composant correspondant est `resources/js/pages/Posts/Index.vue`.

***

## Syntaxe des templates Vue

Voici les directives de template de base nécessaires pour lire et écrire le code d'un starter kit.

#### `{{ }}` — interpolation de variables

Utilisez les doubles accolades pour intégrer des valeurs ou expressions JavaScript dans le template.

```vue theme={null}
<script setup>
const name = 'le monde'
const count = 3
</script>

<template>
    <p>Bonjour, {{ name }} !</p>
    <p>Le double vaut {{ count * 2 }}</p>
</template>
```

#### `v-if` — branchement conditionnel

```vue theme={null}
<template>
    <p v-if="isLoggedIn">Bienvenue !</p>
    <p v-else-if="role === 'admin'">Connecté en tant qu'administrateur</p>
    <a v-else href="/login">Se connecter</a>
</template>
```

Équivalent à `{#if}` de Svelte ou à l'opérateur ternaire de React.

#### `v-for` — rendu de listes

```vue theme={null}
<template>
    <ul>
        <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
</template>
```

Pour une mise à jour différentielle efficace, spécifiez toujours `:key`. Équivalent à `Array.map()` de React.

#### `v-model` — liaison bidirectionnelle

Avec `v-model`, vous pouvez synchroniser en bidirectionnel la valeur d'un élément de formulaire et une variable réactive.

```vue theme={null}
<script setup>
import { ref } from 'vue'

const title = ref('')
const agreed = ref(false)
const role = ref('viewer')
</script>

<template>
    <!-- Champ texte -->
    <input v-model="title" type="text" />
    <p>Saisie en cours : {{ title }}</p>

    <!-- Case à cocher -->
    <input v-model="agreed" type="checkbox" />
    <p>Accord : {{ agreed }}</p>

    <!-- Liste déroulante -->
    <select v-model="role">
        <option value="viewer">Lecteur</option>
        <option value="editor">Éditeur</option>
        <option value="admin">Administrateur</option>
    </select>
</template>
```

#### `:` (v-bind) et `@` (v-on)

* `:attr="value"` — liaison d'une valeur dynamique à un attribut HTML (forme abrégée de `v-bind:attr`)
* `@event="handler"` — enregistrement d'un écouteur d'événement (forme abrégée de `v-on:event`)

```vue theme={null}
<template>
    <!-- Liaison d'attribut dynamique -->
    <img :src="imageUrl" :alt="imageAlt" />

    <!-- Gestionnaires d'événements -->
    <button @click="handleClick">Cliquer</button>
    <form @submit.prevent="handleSubmit">...</form>
</template>
```

***

## Bases des composants de page

Les composants de page Inertia sont de simples composants Vue. Les données passées depuis les contrôleurs Laravel sont reçues comme props.

### Contrôleur

```php theme={null}
// app/Http/Controllers/PostController.php
use Inertia\Inertia;
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        return Inertia::render('Posts/Index', [
            'posts' => Post::latest()->paginate(10),
        ]);
    }
}
```

### Composant de page Vue

```vue theme={null}
<!-- resources/js/pages/Posts/Index.vue -->
<script setup>
import { Link } from '@inertiajs/vue3'

defineProps({
    posts: Object,
})
</script>

<template>
    <div>
        <h1>Liste des publications</h1>
        <article v-for="post in posts.data" :key="post.id">
            <h2>
                <Link :href="`/posts/${post.id}`">{{ post.title }}</Link>
            </h2>
            <p>{{ post.created_at }}</p>
        </article>
    </div>
</template>
```

Il suffit de déclarer les props avec `defineProps()` pour utiliser dans le template les données passées par le contrôleur. Aucune API REST n'a besoin d'être définie.

***

## Composant `Link`

Grâce au composant `<Link>` fourni par `@inertiajs/vue3`, les transitions de page se font via XHR, évitant un rechargement complet du navigateur.

```vue theme={null}
<script setup>
import { Link } from '@inertiajs/vue3'
</script>

<template>
    <!-- Lien de base -->
    <Link href="/posts">Liste des publications</Link>

    <!-- Lien avec méthode POST (suppression, etc.) -->
    <Link href="/posts/1" method="delete" as="button" type="button">
        Supprimer
    </Link>

    <!-- Préchargement (récupération anticipée au survol) -->
    <Link href="/posts/1" preload>Voir la publication</Link>
</template>
```

Vous pouvez l'écrire comme une balise `<a>` classique, mais en coulisses, Inertia ne remplace que le composant de page, offrant une expérience proche d'une SPA.

***

## Composant `Form`

Le composant `<Form>` fourni par `@inertiajs/vue3` est le style recommandé pour la soumission de formulaires, utilisé dans les écrans d'authentification des starter kits. On spécifie `action` et `method` en props et on accède à `errors` et `processing` avec `v-slot`.

### Utilisation de base

```vue theme={null}
<script setup>
import { Form } from '@inertiajs/vue3'
</script>

<template>
    <Form action="/posts" method="post" class="flex flex-col gap-4" v-slot="{ errors, processing }">
        <div>
            <label for="title">Titre</label>
            <input id="title" name="title" type="text" required />
            <p v-if="errors.title" class="error">{{ errors.title }}</p>
        </div>

        <div>
            <label for="content">Contenu</label>
            <textarea id="content" name="content"></textarea>
            <p v-if="errors.content" class="error">{{ errors.content }}</p>
        </div>

        <button type="submit" :disabled="processing">
            {{ processing ? 'Envoi en cours...' : 'Publier' }}
        </button>
    </Form>
</template>
```

`v-slot="{ errors, processing }"` correspond à la syntaxe des slots scoped de Vue ; le composant `Form` calcule et transmet automatiquement ces valeurs. Pour les champs de formulaire, on utilise l'attribut natif HTML `name` au lieu de `v-model`, permettant le fonctionnement de la collecte standard des données du navigateur.

### Modèle du starter kit

Le starter kit utilise [Wayfinder](/fr/blog/wayfinder-introduction) pour gérer les routes sous forme d'objets. `store.form()` retourne un objet contenant `action` et `method` de l'objet route, et vous le passez à `<Form>` par spread avec `v-bind`.

```vue theme={null}
<script setup lang="ts">
import { Form } from '@inertiajs/vue3'
import { store } from '@/routes/login'
</script>

<template>
    <Form
        v-bind="store.form()"
        :reset-on-success="['password']"
        v-slot="{ errors, processing }"
        class="flex flex-col gap-6"
    >
        <!-- Contenu du formulaire -->
    </Form>
</template>
```

Les champs spécifiés dans `reset-on-success` sont automatiquement réinitialisés lorsque la soumission réussit. Utilisez-le pour les champs que vous souhaitez vider après l'envoi, comme les champs de mot de passe.

<Info>
  Si vous n'utilisez pas Wayfinder, passer directement l'URL comme `action="/login"` fonctionne de la même manière.
</Info>

***

## Helper `useForm`

Pour le traitement des formulaires, utilisez le helper `useForm` de `@inertiajs/vue3`. La gestion de l'état, la soumission et l'affichage des erreurs de validation s'implémentent simplement.

### Côté contrôleur

```php theme={null}
// app/Http/Controllers/PostController.php
class PostController extends Controller
{
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title'   => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
        ]);

        Post::create($validated + ['user_id' => auth()->id()]);

        return redirect()->route('posts.index')
            ->with('success', 'Publication créée.');
    }
}
```

### Composant de formulaire Vue

```vue theme={null}
<!-- resources/js/pages/Posts/Create.vue -->
<script setup>
import { useForm } from '@inertiajs/vue3'

const form = useForm({
    title: '',
    content: '',
})

function submit() {
    form.post('/posts')
}
</script>

<template>
    <form @submit.prevent="submit">
        <div>
            <label>Titre</label>
            <input v-model="form.title" type="text" />
            <p v-if="form.errors.title" class="error">{{ form.errors.title }}</p>
        </div>

        <div>
            <label>Contenu</label>
            <textarea v-model="form.content"></textarea>
            <p v-if="form.errors.content" class="error">{{ form.errors.content }}</p>
        </div>

        <button type="submit" :disabled="form.processing">
            {{ form.processing ? 'Envoi en cours...' : 'Publier' }}
        </button>
    </form>
</template>
```

Voici un résumé des principales propriétés retournées par `useForm`.

| Propriété / méthode | Description                                                   |
| ------------------- | ------------------------------------------------------------- |
| `form.data`         | Objet de données du formulaire                                |
| `form.errors`       | Erreurs de validation (accessibles par nom de champ)          |
| `form.processing`   | `true` pendant l'envoi (à utiliser pour désactiver le bouton) |
| `form.isDirty`      | `true` si modifié par rapport à la valeur initiale            |
| `form.post(url)`    | Envoi via une requête POST                                    |
| `form.put(url)`     | Envoi via une requête PUT (mise à jour)                       |
| `form.delete(url)`  | Envoi via une requête DELETE                                  |
| `form.reset()`      | Réinitialise le formulaire à sa valeur initiale               |

Lorsque des erreurs de validation sont retournées, `useForm` affiche les erreurs tout en conservant le contenu saisi. Combiné à `v-model`, cela offre une expérience de formulaire fluide.

***

## Données partagées (Shared Data)

Les données communes à toutes les pages (informations utilisateur connectées, messages flash, etc.) sont définies via la méthode `share()` du middleware `HandleInertiaRequests`.

```php theme={null}
// app/Http/Middleware/HandleInertiaRequests.php
use Illuminate\Http\Request;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
    public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            'auth' => [
                'user' => $request->user()
                    ? $request->user()->only('id', 'name', 'email')
                    : null,
            ],
            'flash' => [
                'success' => $request->session()->get('success'),
                'error'   => $request->session()->get('error'),
            ],
        ]);
    }
}
```

Pour accéder aux données partagées depuis un composant Vue, utilisez `usePage()`.

```vue theme={null}
<script setup>
import { computed } from 'vue'
import { usePage } from '@inertiajs/vue3'

const page = usePage()

// Accès aux données partagées
const user = computed(() => page.props.auth.user)
const flash = computed(() => page.props.flash)
</script>

<template>
    <header>
        <span v-if="user">{{ user.name }}</span>
        <span v-else>Invité</span>
    </header>

    <div v-if="flash.success" class="alert-success">
        {{ flash.success }}
    </div>
</template>
```

<Info>
  Les données partagées sont incluses dans chaque requête ; il est donc recommandé de les limiter au strict nécessaire. En les enveloppant dans une évaluation paresseuse avec `fn()`, elles ne sont évaluées que lorsqu'elles sont réellement consultées.
</Info>

***

## Bases de la réactivité de Vue 3

Voici les API de réactivité de Vue 3 à connaître pour développer avec Inertia × Vue.

### `ref` — valeur réactive primitive

```vue theme={null}
<script setup>
import { ref } from 'vue'

const count = ref(0)
const isOpen = ref(false)

// Accès via .value (inutile dans le template)
count.value++
</script>

<template>
    <p>{{ count }}</p>
    <button @click="isOpen = !isOpen">Basculer</button>
</template>
```

### `computed` — propriété calculée

```vue theme={null}
<script setup>
import { ref, computed } from 'vue'

const posts = ref([])

const publishedPosts = computed(() =>
    posts.value.filter(post => post.published)
)
</script>
```

### `onMounted` — traitement après montage

```vue theme={null}
<script setup>
import { onMounted } from 'vue'

onMounted(() => {
    console.log('Le composant a été monté')
})
</script>
```

***

## Résumé

Vue.js s'accorde bien avec Laravel, et sa force s'exprime tout particulièrement dans une configuration « monolithe moderne » via Inertia.

| Élément               | Rôle                                              |
| --------------------- | ------------------------------------------------- |
| Contrôleur Laravel    | Routage, récupération de données, validation      |
| `Inertia::render()`   | Passe des données du contrôleur au composant Vue  |
| Composant de page Vue | Reçoit les props et rend l'UI                     |
| `useForm`             | Gestion d'état, soumission, affichage des erreurs |
| Composant `Link`      | Transition de page sans rechargement complet      |
| `usePage().props`     | Accès aux données partagées                       |

Avec Inertia × Vue, vous profitez à la fois de la simplicité du back-end Laravel et de l'UI réactive de Vue. Créez un projet avec un starter kit et vous pourrez commencer à développer immédiatement, écrans d'authentification inclus.

<Card title="Documentation officielle d'Inertia.js" icon="book-open" href="https://inertiajs.com">
  Pour toutes les fonctionnalités d'Inertia v3, consultez la documentation officielle.
</Card>


## Related topics

- [Introduction à React — bases pour l'utiliser avec Inertia × Laravel](/fr/blog/react-introduction.md)
- [Introduction à Svelte — bases pour l'utiliser avec Inertia × Laravel](/fr/blog/svelte-introduction.md)
- [Construire une SPA avec Inertia.js](/fr/blog/inertia-introduction.md)
- [Frontend](/fr/frontend.md)
- [Introduction à Eloquent](/fr/eloquent.md)
