# SvelteKit form actions: validation and progressive enhancement

A SvelteKit form action validates on the server and returns fail() without reloading the page. Here is where the logic belongs.

> Page: https://ui.eneawork.it/blog/sveltekit-form-actions
> Markdown: https://ui.eneawork.it/blog/sveltekit-form-actions.md

*2026-11-01*

Una form action in SvelteKit è una funzione esportata da +page.server.ts: riceve la richiesta, valida i dati e restituisce fail() o lancia redirect(). Il form funziona anche senza JavaScript, perché resta un POST normale.

Il pacchetto @sveltejs/kit ha 4.473.234 download settimanali nella settimana 23-29 ottobre 2026, letto da api.npmjs.org il 1 novembre 2026. Il catalogo EneUI misura 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. Ogni comando qui sotto gira in locale, senza account.

## L’action minima

import { fail, redirect } from "@sveltejs/kit"; import type { Actions } from "./$types"; export const actions = { default: async ({ request }) => { const data = await request.formData(); const email = String(data.get("email") ?? "").trim(); if (!email.includes("@")) { return fail(400, { email, message: "Email non valida" }); } await subscribe(email); throw redirect(303, "/grazie"); }, } satisfies Actions;

Il codice 303 dopo un POST evita che un refresh ripeta l’invio. redirect(307) conserva il metodo, quindi il refresh diventa un secondo POST e l’iscrizione arriva due volte.

## Mostrare l’errore senza perdere i dati

import { enhance } from "$app/forms"; let { form } = $props(); Iscriviti {#if form?.message}{form.message}{/if}

Con use:enhance il POST resta un POST, ma senza ricaricare la pagina. Se togli la direttiva il form continua a funzionare: è questo che rende l’enhancement progressivo e non un requisito.

## Dove finisce la validazione

La regola è una sola: la validazione che protegge i dati sta nell’action. Il controllo nel browser serve solo alla velocità, e non sostituisce nulla.

## Errori frequenti

## Il limite noto

Le form actions hanno bisogno di un server. Con adapter-static non esistono: il form deve chiamare un endpoint esterno o una route API su un’altra origine, e perdi la sessione lato server.

## Comandi

npm create svelte@latest my-app npx svelte-kit sync

Dal catalogo: svelte-bits, flowbite-svelte e il blocco logo Svelte. Le guide: lo store che non si aggiorna e svelte-bits misurata; il confronto: Svelte contro React sui siti di contenuto.

## FAQ

### Perché il form restituisce 405?

La form action accetta solo POST con la stessa origine. Un link GET verso la pagina o una fetch senza metodo POST produce 405.

### Come leggo i dati inviati?

Con request.formData() dentro l’action. Il risultato è un oggetto FormData, quindi ogni valore va convertito in stringa.

### A cosa serve il campo form nella pagina?

Contiene ciò che l’action restituisce con fail: serve a rimostrare i valori e il messaggio di errore senza ricaricare la pagina.

### Perché redirect non funziona?

redirect va lanciato con throw, oppure restituito come valore. Se lo chiami e lo ignori, l’esecuzione continua e la risposta non viene reindirizzata.

### Funziona con più form nella stessa pagina?

Sì, con action nominate: ogni form punta a un nome dopo la barra e la action esporta la chiave con lo stesso nome.
