Lesson 19 / 25
Form Actions and use:enhance
Progressively enhanced writes.
Forms that work without JavaScript
A +page.server.ts can export actions: a default action or named actions targeted with action="?/create". An action receives the request (read await request.formData()), cookies, locals and params. Return data to show a result, or fail(400, { ... }) to return a validation failure with a status code; the page reads the latest result through the form prop. A plain <form method="POST"> works with JavaScript disabled. Adding use:enhance from $app/forms progressively enhances it: the form submits with fetch, updates form, reruns load functions and avoids a full page reload. You can pass a callback to enhance to show pending states or customise the update.
The server side of SvelteKit
Form actions handle writes, +server.ts files expose HTTP endpoints, and hooks run on every request.
A validated signup action
Server action plus enhanced form.
<!-- src/routes/signup/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
import type { Actions } from './$types';
import { createUser } from '$lib/server/users';
export const actions = {
default: async ({ request }) => {
const data = await request.formData();
const email = String(data.get('email') ?? '');
if (!email.includes('@')) {
return fail(400, { email, error: 'Enter a valid email' });
}
await createUser(email);
redirect(303, '/welcome');
}
} satisfies Actions;
-->
<!-- src/routes/signup/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms';
import type { PageProps } from './$types';
let { form }: PageProps = $props();
let pending = $state(false);
</script>
<form method="POST" use:enhance={() => {
pending = true;
return async ({ update }) => { await update(); pending = false; };
}}>
<input name="email" type="email" value={form?.email ?? ''} />
{#if form?.error}<p role="alert">{form.error}</p>{/if}
<button disabled={pending}>{pending ? 'Signing up...' : 'Sign up'}</button>
</form>Validate on the server always
Browser validation attributes improve the experience, but the action must validate again because requests can be sent without your form. A schema library such as Zod helps.
Quick check: What does use:enhance add to a SvelteKit form?
- It is required or the form cannot submit
- Server-side validation
- Automatic database writes
- Submission via fetch without a full page reload, while still working without JavaScript
Answer
Submission via fetch without a full page reload, while still working without JavaScript — Progressive enhancement layers on top of plain HTML forms.