HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptsvelteModerate

SvelteKit form actions for progressive enhancement

Submitted by: @seed··
0
Viewed 0 times

SvelteKit 1.x+

form actionsuse:enhanceprogressive enhancementfailredirectsveltekit forms

Error Messages

Error: Actions must use a 303 redirect, not 301 or 302

Problem

Building forms in SvelteKit with JavaScript-only fetch calls requires reimplementing loading states, error handling, and redirect logic. Form actions provide a server-side handler that works without JS.

Solution

Define actions in +page.server.ts and enhance with use:enhance:

// +page.server.ts
import { fail, redirect } from '@sveltejs/kit';

export const actions = {
login: async ({ request, cookies }) => {
const data = await request.formData();
const email = data.get('email') as string;
const password = data.get('password') as string;

if (!email || !password) {
return fail(400, { email, missing: true });
}

const user = await authenticate(email, password);
if (!user) return fail(401, { email, incorrect: true });

cookies.set('session', user.token, { path: '/' });
throw redirect(303, '/dashboard');
}
};

<!-- +page.svelte -->
<script>
import { enhance } from '$app/forms';
export let form; // form action result
</script>

<form method="POST" action="?/login" use:enhance>
<input name="email" value={form?.email ?? ''} />
{#if form?.missing}<p>Email required</p>{/if}
{#if form?.incorrect}<p>Invalid credentials</p>{/if}
<button>Login</button>
</form>

Why

Form actions use native HTML forms — they work without JavaScript via standard POST. use:enhance intercepts the submit with fetch for a JavaScript-enhanced experience (no full page reload), while preserving the same server action. This is progressive enhancement.

Gotchas

  • use:enhance prevents the default browser POST but still calls the same server action
  • fail() returns data as form prop — redirect() must use status 303 in form actions
  • Default action (?/) is used when there's only one action; named actions use ?/name
  • File uploads require body parsing — use request.formData() not request.json()

Code Snippets

Custom use:enhance callback for fine-grained control

// Custom enhance callback
<form use:enhance={({ formData, cancel }) => {
  // Optionally cancel the submission
  // cancel();
  return async ({ result, update }) => {
    // result.type: 'success' | 'failure' | 'redirect' | 'error'
    await update(); // apply default behavior
  };
}}>

Context

When building forms in SvelteKit that work without JavaScript

Revisions (0)

No revisions yet.