Forms

Forms in Swift Rust work the way you'd expect in React, with one twist: server actions let you handle the submission without writing a separate API route.

A simple form

app/contact/page.tsx
import { submitContact } from "./actions";

export default function ContactPage() {
  return (
    <form action={submitContact}>
      <input name="email" type="email" required />
      <textarea name="message" required />
      <button type="submit">Send</button>
    </form>
  );
}
app/contact/actions.ts
"use server";

import { revalidatePath } from "swift-rust/router";

export async function submitContact(formData: FormData) {
  const email = formData.get("email");
  const message = formData.get("message");
  await db.messages.create({ data: { email, message } });
  revalidatePath("/contact");
}

Client-side state

For forms that need optimistic updates or progressive enhancement, mark the component with "use client" and use useState + fetch.

usage
"use client";
import { useState } from "react";

export function NewsletterForm() {
  const [email, setEmail] = useState("");
  const [status, setStatus] = useState<"idle" | "loading" | "done">("idle");

  async function onSubmit(e: React.FormEvent) {
    e.preventDefault();
    setStatus("loading");
    await fetch("/api/subscribe", { method: "POST", body: JSON.stringify({ email }) });
    setStatus("done");
  }

  return (
    <form onSubmit={onSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <button disabled={status === "loading"}>Subscribe</button>
    </form>
  );
}

Validation

The framework doesn't ship a validation library. We recommend zod for parsing form data and API request bodies.