# Add a contact form to a Next.js site

> Add a contact form to Next.js with SiteBackend - a plain HTML form or a client component with fetch. Works with static export.

Source: https://sitebackend.com/docs/forms/nextjs · Updated: 2026-09-28

SiteBackend works with any Next.js setup, including `output: "export"`, because the form posts straight to SiteBackend.

## Option 1: a plain form (no JavaScript)

A Server Component is enough. The browser posts the form and SiteBackend redirects back.

```tsx title="app/contact/page.tsx"
export default function ContactPage() {
  return (
    <form action="https://api.sitebackend.com/forms/YOUR_FORM_ID" method="POST">
      <input type="email" name="email" required />
      <textarea name="message" required />
      <input type="text" name="_gotcha" tabIndex={-1} autoComplete="off" hidden />
      <button type="submit">Send</button>
    </form>
  );
}
```

## Option 2: a client component with fetch

Stay on the page and show your own messages.

```tsx title="app/contact/contact-form.tsx"
"use client";

import { useState } from "react";

const ENDPOINT = process.env.NEXT_PUBLIC_SITEBACKEND_FORM!;

export function ContactForm() {
  const [status, setStatus] = useState<"idle" | "sending" | "sent" | "error">("idle");
  const [error, setError] = useState("");

  async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setStatus("sending");
    const res = await fetch(ENDPOINT, {
      method: "POST",
      body: new FormData(event.currentTarget),
      headers: { Accept: "application/json" },
    });
    const result = await res.json();
    if (result.ok) {
      setStatus("sent");
    } else {
      setError(result.error);
      setStatus("error");
    }
  }

  if (status === "sent") return <p>Thanks! We'll be in touch.</p>;
  return (
    <form onSubmit={onSubmit}>
      <input type="email" name="email" required />
      <textarea name="message" required />
      <button type="submit" disabled={status === "sending"}>
        {status === "sending" ? "Sending…" : "Send"}
      </button>
      {status === "error" && <p role="alert">{error}</p>}
    </form>
  );
}
```

```bash title=".env.local"
NEXT_PUBLIC_SITEBACKEND_FORM=https://api.sitebackend.com/forms/YOUR_FORM_ID
```

## Local development

If you use allowed origins, add `http://localhost:3000`.

## Show testimonials too

SiteBackend can also collect testimonials from your customers and show them on your site. See add testimonials to a Next.js site.
