Zurück zur Startseite

typed-form-actions für Next.js-Formulare mit Zod

Die typed-form-actions Bibliothek vereinfacht das Erstellen getypter Formulare im Next.js App Router. Automatisiert FormData-Parsing, Zod-Validierung und React-Zustandsverwaltung ohne Verlust nativer HTML-Formulare. Geeignet für server-first Ansatz mit minimalem Client-JS.

typed-form-actions: native getypte Next.js-Formulare
Advertisement 728x90

typed-form-actions: Typsichere Formulare für Native Formulare in Next.js

Next.js-Entwickler haben oft mit repetitivem Code zu kämpfen, wenn es um das Verarbeiten von Formularen geht: Das Parsen von FormData, die Erstellung verschachtelter Strukturen, die Validierung mit Zod, die Umwandlung von Fehlern für die Benutzeroberfläche und die Verwaltung von useActionState. Die Bibliothek typed-form-actions automatisiert diese Aufgaben und behält dabei native HTML-Formulare sowie einen server-first-Ansatz bei.

Der Kerngedanke besteht darin, FormData, Zod und useActionState zu einer typsicheren Schicht zusammenzuführen. Die Formulare bleiben standardmäßig, erhalten aber automatisch Typisierung, Fehlerbehandlung und den Zustand "wird bearbeitet" – alles ohne Boilerplate.

Der Schmerz ohne Abstraktion

In einem typischen Server-Action-Fluss mit Zod sieht man Folgendes:

Google AdInline article slot
  • Extrahieren von FormData aus der Anfrage.
  • Manuelles Parsen der Felder in ein Objekt.
  • Validierung anhand eines Schemas.
  • Umwandlung von Zod-Fehlern in Record<string, string[]>.
  • Rückgabe eines standardisierten Zustands mit values, fieldErrors und formError.
  • Auf der Client-Seite: manuelle Bindung von defaultValue, aria-invalid und Fehlerbehandlung.

Beispieltypischer Code:

"use server";
import { z } from "zod";

const contactSchema = z.object({
  name: z.string().min(2, "Name ist zu kurz."),
  email: z.string().email("Gib eine gültige E-Mail-Adresse ein."),
  message: z.string().min(10, "Nachricht ist zu kurz."),
});

export async function sendMessage(prevState: any, formData: FormData) {
  const rawValues = {
    name: formData.get("name"),
    email: formData.get("email"),
    message: formData.get("message"),
  };

  const parsed = contactSchema.safeParse(rawValues);
  if (!parsed.success) {
    return {
      status: "error",
      values: rawValues,
      data: null,
      formError: "Bitte korrigiere die hervorgehobenen Felder und versuche es erneut.",
      fieldErrors: parsed.error.flatten().fieldErrors,
      submittedAt: Date.now(),
    };
  }
  // ...
}

Dieses Muster wiederholt sich bei jeder Form. Mit Arrays, Checkboxen oder verschachtelten Feldern (wie profile.name, links[0].href) wächst der Code exponentiell.

Bibliotheks-API

Die Bibliothek basiert auf zwei zentralen Funktionen:

Google AdInline article slot

createFormAction

Akzeptiert ein Zod-Schema und einen Handler und liefert eine sofort verwendbare Server-Action:

import { createFormAction } from "typed-form-actions";
import { z } from "zod";

const newsletterSchema = z.object({
  email: z.string().email("Gib eine gültige E-Mail-Adresse ein."),
  topics: z.array(z.string()).min(1, "Wähle mindestens ein Thema."),
  marketing: z
    .preprocess((value) => value === "on", z.boolean())
    .default(false),
});

export const subscribeAction = createFormAction({
  schema: newsletterSchema,
  async handler(values) {
    return {
      message: `Abonniert ${values.email}`,
      topicsCount: values.topics.length,
    };
  },
});

useActionForm

Ein clientseitiger Hook, der auf useActionState aufbaut und eine saubere API bietet:

"use client";

import { useActionForm } from "typed-form-actions/react";

import { subscribeAction } from "./actions";

export function NewsletterForm() {
  const form = useActionForm(subscribeAction);

  return (
    <form action={form.action}>
      <label>
        E-Mail
        <input {...form.getInputProps("email", { id: "email", type: "email" })} />
        {form.getFieldError("email") ? (
          <p id={form.getFieldErrorId("email")}>
            {form.getFieldError("email")}
          </p>
        ) : null}
      </label>

      <fieldset>
        <legend>Themen</legend>
        <label>
          <input
            {...form.getInputProps("topics", {
              type: "checkbox",
              value: "react",
            })}
          />
          React
        </label>
        {/* Ähnlich für andere Checkboxen */}
      </fieldset>

      {form.formError ? <p>{form.formError}</p> : null}

      <button disabled={form.isPending} type="submit">
        {form.isPending ? "Speichern..." : "Abonnieren"}
      </button>
    </form>
  );
}

Hinter den Kulissen

Parsen von FormData

Die Bibliothek wandelt flache FormData in verschachtelte Objekte um:

Google AdInline article slot

Eingabe:

{
  "profile.name": "Ada",
  "tags[]": ["react", "next"],
  "links[0].href": "/docs"
}

Ausgabe:

{
  profile: { name: "Ada" },
  tags: ["react", "next"],
  links: [{ href: "/docs" }]
}

Unterstützt Pfade wie profile.name, links[0].href und wiederholte Felder.

Vereinheitlichter FormActionState

type FormActionState<TValues, TResult> = {
  status: "idle" | "success" | "error";
  values: Partial<TValues>;
  data: TResult | null;
  fieldErrors: Record<string, string[]>;
  formError: string | null;
  submittedAt: number | null;
};

useActionForm generiert automatisch:

  • isPending
  • getFieldError(field)
  • getFieldErrorId(field)
  • defaultValue / defaultChecked
  • aria-invalid / aria-describedby

Vergleich mit react-hook-form

| Aspekt | typed-form-actions | react-hook-form |

|--------|-------------------|-----------------|

| Native Formulare | ✅ | ❌ (client-seitig) |

| Server Actions | ✅ | Über Adapter |

| Client-JavaScript | Minimal | Signifikant |

| Zod-Integration | Native | Über Resolver |

| Komplexe Formulare | Grundunterstützung | Vollständige Unterstützung |

Diese Bibliothek konkurriert nicht mit RHF – sie löst das Problem des server-first-Ansatzes für Formulare in Next.js App Router.

Aktuelle Funktionen

  • Parsen von FormData, URLSearchParams und einfachen Objekten
  • Verschachtelte Strukturen und Arrays
  • Zod-Validierung
  • Vorhersehbarer FormActionState
  • React-API für Fehler und Zustände
  • End-to-end-Typisierung

Einschränkungen

  • Kein Adapter für react-hook-form
  • Komplexe Objekt-Arrays benötigen Nachbearbeitung
  • Dateien und exotische Eingabefelder werden nicht abgedeckt
  • API kann sich ändern

Was am wichtigsten ist

  • Boilerplate-Automatisierung: Parsing, Validierung, Fehler – kein manueller Code
  • Native Formulare: Standard-<form>-Elemente, keine unkontrollierten Komponenten
  • Typsicherheit: End-to-end von Schema bis UI
  • Server-first: Minimaler Client-JavaScript, maximale Plattformvorteile
  • Vorhersehbarkeit: Konsistenter FormActionState über alle Formulare hinweg

— Editorial Team

Advertisement 728x90

Weiterlesen