> ## 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 Svelte — le basi per usarlo con Inertia × Laravel

> Guida introduttiva all'uso di Svelte con Laravel + Inertia.js. Spiega in modo pratico l'approccio basato su compiler, la sintassi delle rune di Svelte 5 e gli hook Svelte di Inertia come useForm e usePage.

## Cos'è Svelte

[Svelte](https://svelte.jp/) occupa una posizione originale tra i framework JavaScript. Mentre React e Vue funzionano come **librerie a runtime**, Svelte funziona come **compilatore**. In fase di build converte i componenti in JavaScript puro, quindi non serve inviare al browser codice framework aggiuntivo.

La caratteristica principale di Svelte è che **non usa un Virtual DOM**. Quando lo stato cambia, il codice generato in compilazione da Svelte aggiorna direttamente il DOM. Il risultato è una UI molto leggera e veloce.

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

### Le rune di Svelte 5

Con Svelte 5 (rilasciato nel 2024) è stato introdotto un nuovo sistema di reattività chiamato **Runes**. Si dichiarano stati reattivi con funzioni speciali (rune) come `$state`, `$derived` ed `$effect`. A differenza della reattività implicita di Svelte 4 e precedenti, il design è esplicito e più prevedibile.

```svelte theme={null}
<script lang="ts">
    let count = $state(0)

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

<button onclick={increment}>{count}</button>
```

<Tip>
  Lo starter kit Svelte di Laravel usa Svelte 5 + TypeScript come standard. Anche gli esempi di questa pagina sono tutti in TypeScript (`lang="ts"`).
</Tip>

***

## Posizione in Laravel

### Storia

Il rapporto tra Svelte e Laravel è molto più recente rispetto a Vue e React: la sua prima adozione ufficiale è l'inclusione negli **starter kit ufficiali**.

```mermaid theme={null}
timeline
    title Il percorso di Laravel e Svelte
    2016 : Rilascio di Svelte 1 (di Rich Harris)
    2019 : Svelte 3 — passaggio a design basato su compiler
    2021 : Inertia.js — la community fornisce un adapter per Svelte
    2024 : Svelte 5 — introduzione della sintassi Runes
    2026 : Laravel 13 — aggiunta ufficiale dello starter kit Svelte (compatibile con Inertia v3)
```

Con **Laravel 13 (2026)** Svelte è stato aggiunto ufficialmente agli starter kit e, di fatto, è diventato una delle scelte frontend ufficiali nell'ecosistema Laravel. È trattato allo stesso livello di Vue e React ed è selezionabile dal prompt interattivo di `laravel new`.

È ancora un framework poco conosciuto tra gli utenti Laravel, ma è caratterizzato da **bundle leggeri grazie al compilatore** e **sintassi semplice**: chi arriva da Vue o React potrebbe sorprendersi della minore quantità di codice necessaria.

### Stile principale attuale: Inertia × Svelte

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

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

    Browser <-->|XHR / full page load| Inertia
    Inertia <-->|Risposta Inertia| Laravel
    Inertia -->|props| Svelte
    Svelte -->|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 **Svelte** nel prompt interattivo, viene tutto configurato automaticamente.

* `inertiajs/inertia-laravel` (adapter lato server)
* `@inertiajs/svelte` (adapter lato client)
* `svelte` + `@sveltejs/vite-plugin-svelte` (Svelte 5 e plugin Vite)
* TypeScript + `svelte-check`
* Tailwind CSS + libreria di componenti shadcn-svelte
* Middleware `HandleInertiaRequests`
* Schermate di autenticazione (login, registrazione, ecc.) già implementate con Inertia + Svelte + TypeScript

### 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/svelte @inertiajs/vite svelte
npm install --save-dev @sveltejs/vite-plugin-svelte svelte-check typescript
```

Aggiungi poi in `vite.config.ts` il plugin Svelte e il plugin Vite di Inertia.

```ts theme={null}
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import inertia from '@inertiajs/vite'

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.ts'],
            refresh: true,
        }),
        svelte(),
        inertia(),
    ],
})
```

Avvia l'app Inertia in `resources/js/app.ts`. Il plugin `@inertiajs/vite` esegue la risoluzione automatica delle pagine e il mount, quindi bastano poche righe nell'entry point.

```ts theme={null}
import { createInertiaApp } from '@inertiajs/svelte'

createInertiaApp()
```

<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 Svelte vanno nella directory `resources/js/pages/`.

```
resources/js/
├── app.ts             # Entry point dell'app Inertia
├── components/        # Componenti UI riutilizzabili
│   └── ui/            # Componenti shadcn-svelte
├── layouts/           # Componenti di layout
│   ├── AppLayout.svelte
│   └── AuthLayout.svelte
├── lib/               # Funzioni utility e moduli rune Svelte
├── pages/             # Componenti pagina Inertia (corrispondono ai nomi dei controller)
│   ├── auth/
│   │   ├── Login.svelte
│   │   └── Register.svelte
│   ├── Dashboard.svelte
│   └── posts/
│       ├── Index.svelte
│       ├── Create.svelte
│       └── Show.svelte
└── types/             # Definizioni di tipo TypeScript
```

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

***

## Struttura di base di un file Svelte

Un file `.svelte` è composto da tre blocchi: **`<script>`, template e `<style>`**.

```svelte theme={null}
<script lang="ts">
    // Logica (TypeScript)
    let name = $state('Laravel')
</script>

<!-- Template (notazione simile all'HTML) -->
<h1>Hello, {name}!</h1>

<style>
    /* CSS con scope (applicato solo a questo componente) */
    h1 {
        color: #ff2d20;
    }
</style>
```

La struttura ricorda i Single File Component (SFC) di Vue, ma il codice del template e dello script è più conciso. `<style>` è per default con scope limitato, quindi non devi preoccuparti dei conflitti di nomi di classe.

### Sintassi del template

#### Espansione di variabili ed espressioni

Nel template si usa `{}` per incorporare valori o espressioni JavaScript.

```svelte theme={null}
<script lang="ts">
    let name = $state('mondo')
    let count = $state(3)
</script>

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

#### `{#if}` — condizionali

```svelte theme={null}
<script lang="ts">
    let isLoggedIn = $state(false)
    let role = $state('editor')
</script>

{#if isLoggedIn}
    <p>Benvenuto!</p>
{:else if role === 'admin'}
    <p>Loggato come amministratore</p>
{:else}
    <a href="/login">Login</a>
{/if}
```

Corrisponde a `v-if` / `v-else` di Vue e all'operatore ternario di React.

#### `{#each}` — rendering di liste

```svelte theme={null}
<script lang="ts">
    type Post = { id: number; title: string }
    let posts = $state<Post[]>([
        { id: 1, title: 'Primo post' },
        { id: 2, title: 'Secondo post' },
    ])
</script>

<ul>
    {#each posts as post (post.id)}
        <li>{post.title}</li>
    {/each}
</ul>
```

`(post.id)` è la specifica della chiave, usata per un aggiornamento differenziale efficiente. Corrisponde a `v-for` di Vue e a `Array.map()` di React.

#### `bind:` — binding bidirezionale

Con `bind:value` puoi sincronizzare bidirezionalmente il valore di un elemento form e una variabile reattiva.

```svelte theme={null}
<script lang="ts">
    let title = $state('')
    let agreed = $state(false)
    let role = $state('viewer')
</script>

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

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

<!-- Select -->
<select bind:value={role}>
    <option value="viewer">Lettore</option>
    <option value="editor">Editor</option>
    <option value="admin">Amministratore</option>
</select>
```

Corrisponde a `v-model` di Vue. In React dovevi scrivere manualmente handler `onChange`; in Svelte, con `bind:`, si scrive in modo dichiarativo.

***

## Le basi del componente pagina

I componenti pagina di Inertia sono normali componenti Svelte. 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 Svelte

In Svelte 5 le props si ricevono con la runa `$props()`.

```svelte theme={null}
<!-- resources/js/pages/posts/Index.svelte -->
<script lang="ts">
    import { Link } from '@inertiajs/svelte'

    type Post = {
        id: number
        title: string
        created_at: string
    }

    type Props = {
        posts: {
            data: Post[]
        }
    }

    let { posts }: Props = $props()
</script>

<div>
    <h1>Elenco dei post</h1>
    {#each posts.data as post (post.id)}
        <article>
            <h2>
                <Link href={`/posts/${post.id}`}>{post.title}</Link>
            </h2>
            <p>{post.created_at}</p>
        </article>
    {/each}
</div>
```

Basta ricevere le props con `$props()` per usare nel template i dati passati dal controller. Non è necessario definire un'API REST.

***

## Componente `Link`

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

```svelte theme={null}
<script lang="ts">
    import { Link } from '@inertiajs/svelte'
</script>

<!-- 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">
    Elimina
</Link>

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

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/svelte` è lo stile consigliato usato negli starter kit per l'invio dei form. Specifichi `action` e `method` come props e descrivi l'interno con **`{#snippet}`**.

### Uso di base

```svelte theme={null}
<script lang="ts">
    import { Form } from '@inertiajs/svelte'
</script>

<Form action="/posts" method="post" class="flex flex-col gap-4">
    {#snippet children({ errors, processing })}
        <div>
            <label for="title">Titolo</label>
            <input id="title" name="title" type="text" required />
            {#if errors.title}
                <p class="error">{errors.title}</p>
            {/if}
        </div>

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

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

`{#snippet children({ errors, processing })}` è la sintassi degli snippet di Svelte, un blocco di contenuto da passare al componente (equivalente agli slot di Vue o alle render props di React). `errors` e `processing` sono calcolati e passati automaticamente dal componente `Form`. Ai campi si assegna l'attributo HTML nativo `name` invece di `bind:value`, 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 lo passi a `<Form>` con lo spread.

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

<Form
    {...store.form()}
    resetOnSuccess={['password']}
    class="flex flex-col gap-6"
>
    {#snippet children({ errors, processing })}
        <!-- Contenuto del form -->
    {/snippet}
</Form>
```

I campi specificati in `resetOnSuccess` vengono ripristinati automaticamente al successo dell'invio. 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>

***

## Hook `useForm`

Per la gestione dei form usa l'hook `useForm` di `@inertiajs/svelte`. 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 Svelte

```svelte theme={null}
<!-- resources/js/pages/posts/Create.svelte -->
<script lang="ts">
    import { useForm } from '@inertiajs/svelte'

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

    function submit(e: SubmitEvent) {
        e.preventDefault()
        form.post('/posts')
    }
</script>

<form onsubmit={submit}>
    <div>
        <label>Titolo</label>
        <input type="text" bind:value={form.data.title} />
        {#if form.errors.title}
            <p class="error">{form.errors.title}</p>
        {/if}
    </div>

    <div>
        <label>Contenuto</label>
        <textarea bind:value={form.data.content}></textarea>
        {#if form.errors.content}
            <p class="error">{form.errors.content}</p>
        {/if}
    </div>

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

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. Combinato con `bind:value` 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 Svelte usa `usePage()`.

```svelte theme={null}
<script lang="ts">
    import { usePage } from '@inertiajs/svelte'

    type SharedProps = {
        auth: {
            user: { id: number; name: string; email: string } | null
        }
        flash: {
            success: string | null
            error: string | null
        }
    }

    const page = usePage<SharedProps>()
</script>

<header>
    {#if page.props.auth.user}
        <span>{page.props.auth.user.name}</span>
    {:else}
        <span>Ospite</span>
    {/if}
</header>

{#if page.props.flash.success}
    <div class="alert-success">{page.props.flash.success}</div>
{/if}
```

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

***

## Reattività di Svelte 5 (Runes)

Ecco le rune di Svelte 5 essenziali per sviluppare con Inertia × Svelte.

### `$state` — stato reattivo

```svelte theme={null}
<script lang="ts">
    let count = $state(0)
    let isOpen = $state(false)
    let items = $state<string[]>([])
</script>

<p>{count}</p>
<button onclick={() => count++}>+1</button>
<button onclick={() => isOpen = !isOpen}>Toggle</button>
```

Le variabili dichiarate con `$state` sono automaticamente reattive. Al cambio di valore il DOM si aggiorna in automatico. Corrisponde a `ref` di Vue o `useState` di React, ma non serve accedere alla proprietà `.value`: aggiornare lo stato equivale a fare l'assegnazione.

### `$derived` — valori derivati

```svelte theme={null}
<script lang="ts">
    let posts = $state<{ title: string; published: boolean }[]>([])

    // Estrae solo i post con published = true
    let publishedPosts = $derived(posts.filter(post => post.published))

    // Quando ci sono più dipendenze
    let summary = $derived.by(() => {
        const total = posts.length
        const published = publishedPosts.length
        return `${published} di ${total} pubblicati`
    })
</script>

<p>{summary}</p>
```

`$derived` viene ricalcolato automaticamente quando cambia una delle dipendenze. Corrisponde a `computed` di Vue o `useMemo` di React.

### `$effect` — effetti collaterali

```svelte theme={null}
<script lang="ts">
    let query = $state('')

    // Eseguito ogni volta che cambia query
    $effect(() => {
        console.log('la query di ricerca è cambiata:', query)

        // Puoi restituire una funzione di cleanup
        return () => {
            console.log('cleanup')
        }
    })
</script>

<input bind:value={query} placeholder="Cerca..." />
```

`$effect` si esegue ogni volta che cambia un valore `$state` da cui dipende. Corrisponde a `useEffect` di React, ma non devi indicare esplicitamente un array di dipendenze: le variabili `$state` usate vengono tracciate automaticamente.

***

## Componenti shadcn-svelte

Gli starter kit includono [shadcn-svelte](https://www.shadcn-svelte.com/). shadcn-svelte è una libreria di componenti con la stessa filosofia di design di shadcn/ui per React: il codice viene copiato nel progetto e puoi personalizzarlo liberamente.

### Aggiungere componenti

```shell theme={null}
npx shadcn-svelte@latest add button
npx shadcn-svelte@latest add input
npx shadcn-svelte@latest add card
```

Eseguendo il comando, il codice sorgente del componente viene posizionato in `resources/js/components/ui/`.

### Utilizzo

```svelte theme={null}
<script lang="ts">
    import { Button } from '@/components/ui/button'
    import { Input } from '@/components/ui/input'
    import * as Card from '@/components/ui/card'
    import { useForm } from '@inertiajs/svelte'

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

    function submit(e: SubmitEvent) {
        e.preventDefault()
        form.post('/login')
    }
</script>

<Card.Root class="w-96">
    <Card.Header>
        <Card.Title>Login</Card.Title>
    </Card.Header>
    <Card.Content>
        <form onsubmit={submit} class="space-y-4">
            <Input
                type="email"
                bind:value={form.data.email}
                placeholder="Email"
            />
            {#if form.errors.email}
                <p class="text-sm text-red-500">{form.errors.email}</p>
            {/if}

            <Input
                type="password"
                bind:value={form.data.password}
                placeholder="Password"
            />

            <Button type="submit" disabled={form.processing} class="w-full">
                {form.processing ? 'Login in corso...' : 'Accedi'}
            </Button>
        </form>
    </Card.Content>
</Card.Root>
```

Gli starter kit contengono già componenti d'uso comune come Button, Input, Card, Dialog e Dropdown. Quelli che vuoi aggiungere puoi introdurli in qualsiasi momento con `npx shadcn-svelte@latest add`.

***

## Conclusioni

Svelte, in combinazione con Laravel, dà il meglio nell'architettura "monolite moderno" tramite Inertia. Grazie al design basato su compilatore, il bundle è piccolo e, con la sintassi delle rune, la reattività è esplicita e facile da comprendere.

| Elemento                 | Ruolo                                             |
| ------------------------ | ------------------------------------------------- |
| Controller Laravel       | Routing, recupero dati e validazione              |
| `Inertia::render()`      | Passa i dati dal controller al componente Svelte  |
| Componente pagina Svelte | Riceve le props con `$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                         |
| shadcn-svelte            | Libreria di componenti standard                   |

Con Inertia × Svelte ottieni un'esperienza di sviluppo che unisce la semplicità del backend Laravel a uno stile di scrittura compatto. 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 Vue.js — le basi per usarlo con Inertia × Laravel](/it/blog/vue-introduction.md)
- [Frontend](/it/frontend.md)
- [Installazione](/it/installation.md)
- [Introduzione all'autenticazione](/it/authentication.md)
