TruForms
Next.js

Next.js contact form

Next.js gives you two ways to handle a contact form: post directly from a Client Component, or proxy through a Route Handler. The direct route needs no server code at all — a "use client" component sends the fields to TruForms and updates state with the result.

Reach for an app/api/contact/route.ts Route Handler only when you want the submission to stay server-side — to attach a server-only secret, run extra validation, or keep the request out of the browser’s network tab. Otherwise the client-side post is simpler and one less moving part, since the access key is public and only identifies the form.

Copy-paste snippet

app/contact/ContactForm.tsx
'use client';

import { FormEvent, useState } from 'react';

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

  async function onSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const form = e.currentTarget;
    setStatus('sending');
    const body = new FormData(form);
    body.append('access_key', 'YOUR_ACCESS_KEY');
    const res = await fetch('https://truforms.truenotech.com/api/submit', { method: 'POST', body });
    const result = await res.json();
    setStatus(result.success ? 'sent' : 'error');
    if (result.success) form.reset();
  }

  return (
    <form onSubmit={onSubmit}>
      <input name="name" required />
      <input name="email" type="email" required />
      <textarea name="message" required />
      <input name="botcheck" type="text" style={{ display: 'none' }} />
      <button disabled={status === 'sending'}>Send</button>
    </form>
  );
}

Replace YOUR_ACCESS_KEY with your form's access key from the dashboard. The access key is public — it only identifies the form.

How it works

  1. 1

    Create a form in the TruForms dashboard and copy its access key.

  2. 2

    Add the client component (note the "use client" directive) and replace YOUR_ACCESS_KEY.

  3. 3

    No backend needed — but you can proxy through a Route Handler if you prefer to keep the call server-side.

Notes for Next.js

  • The `"use client"` directive is required — `fetch` plus `useState` only run in a Client Component, not a Server Component.
  • You don’t need a Route Handler. Add `app/api/contact/route.ts` only if you want to keep the request server-side or attach custom logic, then POST to it instead.
  • Same caveat as React: grab `const form = e.currentTarget` before the await so `form.reset()` doesn’t hit a null after the request.

Other frameworks

Next.js Contact Form (App Router, No Backend) · TruForms