Scaffold a typed SvelteKit form in seconds. Generates a page, a Zod schema, and a matching sveltekit-superforms handler from a single field list, wiring validation end-to-end. Text, number, email, password, URL, date, editor, boolean, select, and file fields each render with the appropriate shadcn-svelte input. A server test is included so the form's POST handler is covered from the moment it lands in your repo.
<script lang="ts">
import { untrack } from "svelte";
import { superForm } from "sveltekit-superforms";
import { zod4Client } from "sveltekit-superforms/adapters";
import { contactSchema } from "$lib/schemas/contact";
import * as Form from "$lib/components/ui/form";
import { Input } from "$lib/components/ui/input";
import { Textarea } from "$lib/components/ui/textarea";
let { data } = $props();
const form = superForm(
untrack(() => data.form),
{
validators: zod4Client(contactSchema),
},
);
const { form: formData } = form;
</script>
<section data-role="content">
<div class="flex justify-between items-center mb-4">
<h1 class="text-3xl font-bold tracking-tight">Contact</h1>
</div>
<div class="bg-card rounded-lg shadow-sm border p-4">
<form method="POST">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<Form.Field {form} name="name" class="col-span-1">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$formData.name} />
{/snippet}
</Form.Control>
<Form.FieldErrors class="contents text-destructive" />
</Form.Field>
<Form.Field {form} name="email" class="col-span-1">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Email</Form.Label>
<Input {...props} type="email" bind:value={$formData.email} />
{/snippet}
</Form.Control>
<Form.FieldErrors class="contents text-destructive" />
</Form.Field>
<Form.Field {form} name="message" class="col-span-2">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Message</Form.Label>
<Textarea {...props} bind:value={$formData.message} />
{/snippet}
</Form.Control>
<Form.FieldErrors class="contents text-destructive" />
</Form.Field>
</div>
<div class="mt-4 flex gap-2 border-t pt-4 -mx-4 px-4">
<Form.Button>Submit</Form.Button>
</div>
</form>
</div>
</section>
import { fail, superValidate } from "sveltekit-superforms";
import { zod4 } from "sveltekit-superforms/adapters";
import { contactSchema } from "$lib/schemas/contact";
import { setFlash } from "sveltekit-flash-message/server";
export const load = async () => {
const form = await superValidate(zod4(contactSchema));
return { form };
};
export const actions = {
default: async ({ request, cookies }) => {
const form = await superValidate(request, zod4(contactSchema));
if (!form.valid) {
return fail(400, { form });
}
setFlash({ type: "toast", message: "Form posted successfully" }, cookies);
return { form };
},
};
import { afterEach, beforeEach, describe, expect, it } from "vitest";
describe("/contact", () => {
describe("GET /contact", () => {
it("should return a 200 status code", async (context) => {
const response = await context.request.get("/contact");
expect(response.status).toBe(200);
});
});
describe("POST /contact", () => {
it("should submit the form successfully", async (context) => {
const response = await context.request
.post("/contact")
.type("form")
.send({
name: "name value",
email: "test-email@example.com",
message: "message value",
});
expect(response.body.status).toBe(200);
});
});
});
import { z } from "zod";
export const contactSchema = z.object({
name: z.string().optional(),
email: z.email().optional(),
message: z.string().optional(),
});