SvelteKit's form actions let you handle form submissions on the server using plain HTML <form> elements. They work without JavaScript (progressive enhancement) and enhance progressively when JS is available.
Defining an Action
Actions live in +page.server.js alongside your load function:
The Form Template
<!-- src/routes/contact/+page.svelte -->
<script>
export let form; // contains action return value (errors, data)
</script>
<form method="POST">
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
<label>
Name
<input name="name" value={form?.name ?? ''} required>
</label>
<label>
Email
<input name="email" type="email" value={form?.email ?? ''} required>
</label>
<label>
Message
<textarea name="message">{form?.msg ?? ''}</textarea>
</label>
<button type="submit">Send</button>
</form>With no JavaScript, this is a full round-trip: form submits → server validates → redirects or returns errors. It works in any browser, including with JavaScript disabled.
Progressive Enhancement with use:enhance
Add use:enhance to intercept the submission with fetch, keeping the page without a full reload:
<script>
import { enhance } from '$app/forms';
export let form;
let loading = false;
</script>
<form method="POST" use:enhance={()=> {
loading= true;
return async ({ update })=> {
await update();
loading= false;
};
}}>
<button disabled={loading}>
{loading ? 'Sending…' : 'Send'}
</button>
</form>use:enhance is just 1 KB and gives you loading states, optimistic UI, and no page flash — all while falling back gracefully without JS.
Named Actions
One page can have multiple actions:
Live Form with Validation
Cookies and Sessions
Actions can read and set cookies for session management: