Superforms

Table of Contents

1. Quickstart

1.1. Validation Schema

The first step is to create a validation schema using a schema library, such as Zod:

// schema.ts
export const personalInformationSchema = z.object({
  name: z.string().optional(),
  email: z.email().optional(),
  phone: z.string().optional(),
  birthday: z.iso.date().optional(),
});

1.2. Load Form

Then, initialize the form and load it into the PageData through the server:

// +page.server.ts
import { superValidate } from 'sveltekit-superforms';
import { zod } from 'sveltekit-superforms/adapters';
import { personalInformationSchema } from './schema';

/** Load member data for the profile page. */
export const load: PageServerLoad = async ({ locals: { supabase } }) => {
  // load personal information form
  const personalInformationForm = await superValidate(zod(personalInformationSchema));

  return {
    personalInformationForm,
  };
}

1.3. Form Actions

1.4. Frontend Form

Use the data loaded in by Superforms in the client to show the form and integrate:

<script lang="ts">
  import { superForm } from "sveltekit-superforms";

  // get page data loaded from server
  let { data } = $props();

  // superforms loaded forms
  const { form: personalInformationForm } = superForm(data.personalInformationForm);
</script>

<form method="POST" action="?/save_personal_information">
  <label class="grid grid-cols-[150px_1fr] mb-2 items-center">
    <div>Name</div>
    <input name="name" type="text" class="border border-muted-b bg-input"
           bind:value={$personalInformationForm.name}>
  </label>
  <label class="grid grid-cols-[150px_1fr] mb-2 items-center">
    <div>Email</div>
    <input name="email" type="email" class="border border-muted-b bg-input"
           bind:value={$personalInformationForm.email}>
  </label>
  <div class="grid grid-cols-2">
    <label class="grid grid-cols-[150px_1fr] mb-2 mr-5 items-center">
      <div>Phone</div>
      <input name="phone" type="tel" class="border border-muted-b bg-input"
             bind:value={$personalInformationForm.phone}>
    </label>
    <label class="grid grid-cols-[150px_1fr] mb-2 ml-5 items-center">
      <div>Birthday</div>
      <input name="birthday" type="date" class="border border-muted-b bg-input"
             bind:value={$personalInformationForm.birthday}>
    </label>
  </div>
  <div class="w-full flex justify-end">
    <button type="submit">
      Save
    </button>
  </div>
</form>

2. Error Handling

2.1. Validation Errors

2.2. Status Messages

For server-side errors that don't pertain to validating any one field or input, use a status message to indicate an error on the front-end.

const { error } = await supabase
  .from('members')
  .update(form.data)
  .eq('email', user.email);
if (error) {
  return message(form, 'Database error.', {
    status: 500
  });
}
Last modified: 2025-05-31 23:21