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

# Introduzione a Vue.js — le basi per usarlo con Inertia × Laravel

> Presentiamo Vue.js, il framework JS più familiare per gli utenti Laravel. Dalla panoramica di Options API / Composition API ai componenti pagina, useForm e dati condivisi con Inertia v3 × Vue 3.

## Cos'è Vue.js

Vue.js (di seguito "Vue") è un framework JavaScript progressivo per costruire interfacce utente. "Progressivo" significa che puoi iniziare da parti piccole e aggiungere funzionalità quando servono: si adatta sia all'inserimento parziale in pagine HTML esistenti sia alla costruzione di SPA di grandi dimensioni.

Il cuore di Vue è la **reattività**. Quando i dati cambiano, il DOM si aggiorna automaticamente, quindi non devi gestire manualmente "quando e quale elemento aggiornare".

<Info>
  In questa pagina spieghiamo la combinazione di Vue 3 e Inertia v3. Lo starter kit di Laravel 13 usa questa configurazione per impostazione predefinita.
</Info>

### Options API e Composition API

Vue 3 offre due stili per scrivere i componenti: **Options API** e **Composition API**.

**Options API** è lo stile tradizionale ereditato da Vue 2. Definisci il componente tramite un oggetto opzioni con `data`, `methods`, `computed`, `mounted`, ecc.

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

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

**Composition API** è lo stile introdotto in Vue 3. Combinandolo con la sintassi `<script setup>` puoi scrivere in modo più conciso. Ha una riusabilità della logica maggiore ed è particolarmente adatto a TypeScript.

```vue theme={null}
<!-- Esempio di 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>
  Gli starter kit di Inertia × Laravel usano come standard lo stile Composition API con `<script setup>`. Anche gli esempi in questa pagina sono tutti in `<script setup>`.
</Tip>

***

## Posizione in Laravel

### Storia

Il rapporto tra Vue e Laravel è di lunga data e inizia con l'adozione di Vue come framework frontend predefinito in **Laravel 5.3 (2016)**. All'epoca Vue era incluso in `package.json` ed era fornito anche il componente d'esempio `resources/js/components/ExampleComponent.vue`.

```mermaid theme={null}
timeline
    title Il percorso di Laravel e Vue
    2016 : Laravel 5.3 — Vue adottato come default
    2019 : Laravel 6 — scaffold Vue spostato nel pacchetto laravel/ui
    2021 : Laravel 8 — starter kit Jetstream + Inertia (Vue)
    2022 : Laravel 9 — passaggio a Vite
    2025 : Laravel 12 — rinnovo degli starter kit (Vue / React)
    2026 : Laravel 13 — starter kit compatibili con Inertia v3
```

Con **Laravel 6 (2019)** lo scaffold di autenticazione è stato scorporato nel pacchetto `laravel/ui` e anche lo scaffold Vue è passato a quel pacchetto. Attualmente lo stile principale è scegliere la configurazione Inertia + Vue tramite gli starter kit di `laravel new`.

Per gli utenti Laravel, Vue è il framework JS più familiare, con risorse di apprendimento in molte lingue.

### Stile principale attuale: Inertia × Vue

Il modo principale di usare Vue in Laravel è **Inertia × Vue**. Inertia realizza l'architettura "monolite moderno" che permette di passare dati dai controller Laravel direttamente ai componenti Vue senza progettare un'API.

```mermaid theme={null}
graph LR
    Browser["Browser"]
    Inertia["Inertia.js<br>(layer adapter)"]
    Laravel["Laravel<br>(controller)"]
    Vue["Vue<br>(componenti pagina)"]

    Browser <-->|XHR / full page load| Inertia
    Inertia <-->|Risposta Inertia| Laravel
    Inertia -->|props| Vue
    Vue -->|rendering| Browser
```

***

## Setup

### Tramite starter kit (consigliato)

Per iniziare un nuovo progetto il modo più semplice è usare lo starter kit.

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

Se scegli **Vue** nel prompt interattivo, viene tutto configurato automaticamente.

* `inertiajs/inertia-laravel` (adapter lato server)
* `@inertiajs/vue3` (adapter lato client)
* `vue` (Vue 3)
* `@vitejs/plugin-vue` (plugin Vite)
* Middleware `HandleInertiaRequests`
* Schermate di autenticazione (login, registrazione, ecc.) già implementate con Inertia + Vue

### Installazione manuale

Per aggiungerlo a un progetto esistente, installa separatamente lato server e lato client.

```shell theme={null}
# Lato server (PHP)
composer require inertiajs/inertia-laravel

# Lato client (JavaScript)
npm install @inertiajs/vue3 vue
npm install --save-dev @vitejs/plugin-vue
```

Aggiungi poi il plugin Vue in `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,
                },
            },
        }),
    ],
})
```

Avvia l'app Inertia in `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>
  Per i dettagli dell'installazione manuale (configurazione del template root, registrazione dei middleware, ecc.) consulta la [documentazione ufficiale di Inertia](https://inertiajs.com/installation).
</Info>

***

## Struttura delle directory

Negli starter kit i componenti pagina Vue vanno nella directory `resources/js/pages/`.

```
resources/js/
├── app.js             # Entry point dell'app Inertia
├── bootstrap.js
├── components/        # Componenti UI riutilizzabili
│   ├── NavBar.vue
│   └── ...
├── layouts/           # Componenti di layout
│   ├── AppLayout.vue
│   └── AuthLayout.vue
└── pages/             # Componenti pagina Inertia (corrispondono ai nomi dei controller)
    ├── Auth/
    │   ├── Login.vue
    │   └── Register.vue
    ├── Dashboard.vue
    └── Posts/
        ├── Index.vue
        ├── Create.vue
        └── Show.vue
```

Scrivendo `Inertia::render('Posts/Index', [...])`, il componente corrispondente è `resources/js/pages/Posts/Index.vue`.

***

## Sintassi dei template Vue

Ecco le direttive di template di base che servono per leggere e scrivere il codice degli starter kit.

#### `{{ }}` — espansione di variabili

Con le doppie parentesi graffe incorpori valori o espressioni JavaScript nel template.

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

<template>
    <p>Ciao, {{ name }}!</p>
    <p>Il doppio è {{ count * 2 }}</p>
</template>
```

#### `v-if` — condizionali

```vue theme={null}
<template>
    <p v-if="isLoggedIn">Benvenuto!</p>
    <p v-else-if="role === 'admin'">Loggato come amministratore</p>
    <a v-else href="/login">Login</a>
</template>
```

Corrisponde a `{#if}` di Svelte o all'operatore ternario di React.

#### `v-for` — rendering di liste

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

Specifica sempre `:key` per un aggiornamento differenziale efficiente. Corrisponde a `Array.map()` di React.

#### `v-model` — binding bidirezionale

Con `v-model` puoi sincronizzare bidirezionalmente il valore di un elemento form e una variabile reattiva.

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

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

<template>
    <!-- Input di testo -->
    <input v-model="title" type="text" />
    <p>In inserimento: {{ title }}</p>

    <!-- Checkbox -->
    <input v-model="agreed" type="checkbox" />
    <p>Accettato: {{ agreed }}</p>

    <!-- Select -->
    <select v-model="role">
        <option value="viewer">Lettore</option>
        <option value="editor">Editor</option>
        <option value="admin">Amministratore</option>
    </select>
</template>
```

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

* `:attr="value"` — bind di un valore dinamico su un attributo HTML (forma abbreviata di `v-bind:attr`)
* `@event="handler"` — registra un listener di evento (forma abbreviata di `v-on:event`)

```vue theme={null}
<template>
    <!-- Bind dinamico di attributi -->
    <img :src="imageUrl" :alt="imageAlt" />

    <!-- Event handler -->
    <button @click="handleClick">Clicca</button>
    <form @submit.prevent="handleSubmit">...</form>
</template>
```

***

## Le basi del componente pagina

I componenti pagina di Inertia sono normali componenti Vue. I dati passati dal controller Laravel arrivano come props.

### Controller

```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),
        ]);
    }
}
```

### Componente pagina Vue

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

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

<template>
    <div>
        <h1>Elenco dei post</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>
```

Basta dichiarare le props con `defineProps()` per usare nel template i dati passati dal controller. Non serve definire un'API REST.

***

## Componente `Link`

Usando il componente `<Link>` di `@inertiajs/vue3`, le transizioni avvengono via XHR ed eviti il full reload del browser.

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

<template>
    <!-- Link di base -->
    <Link href="/posts">Elenco post</Link>

    <!-- Link con metodo POST (ad es. per l'eliminazione) -->
    <Link href="/posts/1" method="delete" as="button" type="button">
        Elimina
    </Link>

    <!-- Preload (fetch anticipato all'hover) -->
    <Link href="/posts/1" preload>Vedi il post</Link>
</template>
```

Si scrive come un normale tag `<a>`, ma dietro le quinte Inertia sostituisce solo il componente di pagina, dando una sensazione da SPA.

***

## Componente `Form`

Il componente `<Form>` fornito da `@inertiajs/vue3` è lo stile consigliato usato dagli starter kit per l'invio dei form. Specifichi `action` e `method` come props e accedi a `errors` e `processing` tramite `v-slot`.

### Uso di 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">Titolo</label>
            <input id="title" name="title" type="text" required />
            <p v-if="errors.title" class="error">{{ errors.title }}</p>
        </div>

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

        <button type="submit" :disabled="processing">
            {{ processing ? 'Invio in corso...' : 'Pubblica' }}
        </button>
    </Form>
</template>
```

`v-slot="{ errors, processing }"` è la sintassi di scoped slot di Vue; il componente `Form` calcola e passa automaticamente questi valori. Ai campi si assegna l'attributo HTML nativo `name` invece di `v-model`, così funziona la raccolta standard dei dati del browser.

### Pattern degli starter kit

Gli starter kit gestiscono le rotte come oggetti tramite [Wayfinder](/it/blog/wayfinder-introduction). `store.form()` restituisce un oggetto contenente `action` e `method` dell'oggetto rotta e viene passato a `<Form>` con `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"
    >
        <!-- Contenuto del form -->
    </Form>
</template>
```

I campi specificati in `reset-on-success` vengono ripristinati automaticamente in caso di invio riuscito. Utile per campi come la password che vuoi svuotare dopo l'invio.

<Info>
  Se non usi Wayfinder puoi passare direttamente l'URL come `action="/login"` e funziona allo stesso modo.
</Info>

***

## Helper `useForm`

Per la gestione dei form usa l'helper `useForm` di `@inertiajs/vue3`. Puoi implementare in modo semplice gestione stato, invio ed errori di validazione.

### Lato controller

```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', 'Post creato.');
    }
}
```

### Componente form 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>Titolo</label>
            <input v-model="form.title" type="text" />
            <p v-if="form.errors.title" class="error">{{ form.errors.title }}</p>
        </div>

        <div>
            <label>Contenuto</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 ? 'Invio in corso...' : 'Pubblica' }}
        </button>
    </form>
</template>
```

Ecco le principali proprietà restituite da `useForm`.

| Proprietà / Metodo | Descrizione                                             |
| ------------------ | ------------------------------------------------------- |
| `form.data`        | Oggetto dati del form                                   |
| `form.errors`      | Errori di validazione (accesso per nome campo)          |
| `form.processing`  | `true` durante l'invio (per disabilitare il pulsante)   |
| `form.isDirty`     | `true` se ci sono modifiche rispetto ai valori iniziali |
| `form.post(url)`   | Invia con richiesta POST                                |
| `form.put(url)`    | Invia con richiesta PUT (update)                        |
| `form.delete(url)` | Invia con richiesta DELETE                              |
| `form.reset()`     | Ripristina il form ai valori iniziali                   |

Quando arrivano errori di validazione, `useForm` mantiene i contenuti inseriti mostrando gli errori. In combinazione con `v-model` offre un'esperienza di form senza interruzioni.

***

## Dati condivisi (Shared Data)

I dati necessari a tutte le pagine (utente loggato, messaggi flash, ecc.) si definiscono nel metodo `share()` del 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'),
            ],
        ]);
    }
}
```

Per accedere ai dati condivisi da un componente Vue usa `usePage()`.

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

const page = usePage()

// Accesso ai dati condivisi
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>Ospite</span>
    </header>

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

<Info>
  Poiché i dati condivisi sono inclusi in ogni richiesta, si consiglia di limitarli allo stretto necessario. Con valutazioni lazy tramite `fn()`, vengono valutati solo quando ci si accede davvero.
</Info>

***

## Basi della reattività di Vue 3

Ecco le API di reattività di Vue 3 essenziali per sviluppare con Inertia × Vue.

### `ref` — valore reattivo primitivo

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

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

// Accesso tramite .value (non serve nel template)
count.value++
</script>

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

### `computed` — proprietà calcolate

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

const posts = ref([])

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

### `onMounted` — elaborazioni dopo il mount

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

onMounted(() => {
    console.log('Il componente è stato montato')
})
</script>
```

***

## Conclusioni

Vue.js ha una grande affinità con Laravel e dà il meglio nell'architettura "monolite moderno" tramite Inertia.

| Elemento              | Ruolo                                         |
| --------------------- | --------------------------------------------- |
| Controller Laravel    | Routing, recupero dati e validazione          |
| `Inertia::render()`   | Passa i dati dal controller al componente Vue |
| Componente pagina Vue | Riceve le props e renderizza la UI            |
| `useForm`             | Gestione stato, invio ed errori del form      |
| Componente `Link`     | Transizioni di pagina senza full reload       |
| `usePage().props`     | Accesso ai dati condivisi                     |

Con Inertia × Vue ottieni sia la semplicità del backend Laravel sia la UI reattiva di Vue. Creando il progetto tramite starter kit, puoi iniziare subito con schermate di autenticazione incluse.

<Card title="Documentazione ufficiale di Inertia.js" icon="book-open" href="https://inertiajs.com">
  Per tutte le funzionalità di Inertia v3 consulta la documentazione ufficiale.
</Card>


## Related topics

- [Introduzione a React — le basi per usarlo con Inertia × Laravel](/it/blog/react-introduction.md)
- [Introduzione a Svelte — le basi per usarlo con Inertia × Laravel](/it/blog/svelte-introduction.md)
- [Costruire una SPA con Inertia.js](/it/blog/inertia-introduction.md)
- [Frontend](/it/frontend.md)
- [Precognition](/it/precognition.md)
