> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formbase.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js App Router

> Submit to Formbase from Next.js App Router pages.

Next.js App Router is a great fit for Formbase because server actions can submit on the server and return a clean JSON response. This avoids browser redirects and gives you full control over the UI.

You can still submit from the client if you want, but server actions are the most reliable pattern.

<Steps>
  <Step title="Create a server action">
    Submit the form data from the server so Formbase returns JSON instead of a redirect.

    ```ts theme={null}
    // app/actions/submit-to-formbase.ts
    'use server';

    export async function submitToFormbase(
      _prevState: { ok: boolean; message: string },
      formData: FormData,
    ) {
      const response = await fetch('https://formbase.dev/s/YOUR_FORM_ID', {
        method: 'POST',
        body: formData,
      });

      if (!response.ok) {
        return { ok: false, message: 'Submission failed.' };
      }

      return { ok: true, message: 'Submitted!' };
    }
    ```

    This works for both text fields and file uploads.
  </Step>

  <Step title="Wire it to a client component">
    ```tsx theme={null}
    'use client';

    import { useFormState } from 'react-dom';
    import { submitToFormbase } from '../actions/submit-to-formbase';

    const initialState = { ok: false, message: '' };

    export default function ContactForm() {
      const [state, formAction] = useFormState(submitToFormbase, initialState);

      return (
        <form action={formAction}>
          <input name="name" placeholder="Name" required />
          <input name="email" type="email" placeholder="Email" required />
          <textarea name="message" required />
          <button type="submit">Send</button>
          {state.message && <p>{state.message}</p>}
        </form>
      );
    }
    ```

    The form posts to your server action, which forwards the submission to Formbase.
  </Step>
</Steps>

## Client-side alternative

If you must submit from the browser, treat a `303` response as success:

```tsx theme={null}
const response = await fetch('https://formbase.dev/s/YOUR_FORM_ID', {
  method: 'POST',
  body: new FormData(event.currentTarget),
  redirect: 'manual',
});

if (response.status === 303 || response.ok) {
  // success
}
```

<Callout type="note">
  Server actions avoid CORS issues and give you a JSON response. Use them when possible.
</Callout>
