Core Concepts
Server Actions
Type-safe server actions with createAction
Form Wire provides createAction for Next.js server actions that validate against your Zod schema and return typed results.
createAction
import { createAction } from "@form-wire/core";
import { z } from "zod";
const schema = z.object({
email: z.email(),
password: z.string().min(8),
});
export const login = createAction(schema, async (data) => {
// data is typed as { email: string; password: string }
const user = await authenticate(data);
return { data: { userId: user.id } };
});Return Types
createAction returns an action compatible with React's useActionState. It returns ActionState<TResult>:
type ActionState<TResult> =
| { success: true; data?: TResult; message?: string }
| { success: false; fieldErrors: Record<string, string[]>; formErrors: string[] };Success
return { data: { id: 1 } }; // ActionSuccess with data
return { message: "Saved!" }; // ActionSuccess with message only
return {}; // ActionSuccess, no data/messageFailure
return { formErrors: ["Something went wrong"] };
return { fieldErrors: { email: ["Already taken"] } };formError Helper
For quick error responses:
import { formError } from "@form-wire/core";
export const register = createAction(schema, async (data) => {
if (await emailExists(data.email)) {
return formError({
fieldErrors: {
email: ["Email already registered"],
},
});
}
// ...
});Throwing Errors
If your action throws a FormWireServerError, it's caught and converted to a failure state:
import { FormWireServerError } from "@form-wire/core";
throw new FormWireServerError({
fieldErrors: { email: ["Invalid"] },
formErrors: ["Please fix the errors above"],
});With Next.js
// app/login/action.ts
"use server";
import { createAction } from "@form-wire/core";
export const login = createAction(schema, async (data) => {
// ...
});
// app/login/page.tsx
import { FormWireProvider, htmlMapper, createFormWire } from "@form-wire/react";
import { login } from "./action";
const Login = createFormWire(schema, { /* config */ });
export default function LoginPage() {
return (
<FormWireProvider mapper={htmlMapper}>
<Login.Form action={login} />
</FormWireProvider>
);
}The form automatically displays field errors and form errors from the action result.