Skip to content

Feedback forms · 5 fields

Client feedback form template

Send it when a project ends, while the details are fresh. The rating gives you a number to compare across projects; the open answer tells you what to repeat and what to fix.

Get the code

Client feedback form

Live demo: try the fields. Submitting sends nothing.

Why these fields

  • Name

    text · required

    Required here so you can follow up. Remove it, and the email field, if you want anonymous feedback; the anonymous feedback template does that.

  • Email

    email · required

    Required for a reply. Say in a sentence why you ask for it.

  • Project

    text · optional

    Optional. Lets you compare feedback across projects of the same kind.

  • Overall rating

    select · optional

    Optional, four steps from Excellent to Poor. Keep the same scale on every project so the numbers stay comparable.

  • Your feedback

    textarea · required

    Required: the answer worth reading. Ask what went well and what you should do differently.

When to use it

Use it after client work: a website, a renovation, a consulting engagement. For ongoing customers of a product, the NPS or customer satisfaction survey templates fit better.

Link it from your closing email or invoice, or set the project name in a hidden field when you send one form per project.

Privacy and GDPR

  • Feedback with a name attached is personal data. Tell clients how you use it, and ask separately before quoting them publicly as a testimonial.
  • Delete or anonymise old feedback once you have acted on it; the rating totals are what you keep.

Choose your stack. Copy your form.

Replace the example endpoint with your Formward endpoint, then adapt the fields to your needs.

<form action="https://forms.formward.eu/f/your-form-id" method="POST">
  <label for="name">Name</label>
  <input type="text" name="name" id="name" required />
  <label for="email">Email</label>
  <input type="email" name="email" id="email" required />
  <label for="project">Project</label>
  <input type="text" name="project" id="project" />
  <label for="rating">Overall rating</label>
  <select name="rating" id="rating">
    <option value="Excellent">Excellent</option>
    <option value="Good">Good</option>
    <option value="Average">Average</option>
    <option value="Poor">Poor</option>
  </select>
  <label for="feedback">Your feedback</label>
  <textarea name="feedback" id="feedback" required></textarea>
  <input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px" aria-hidden="true" />
  <button type="submit">Send</button>
</form>

Accessible by default, and how to keep it that way

  • Every field in the code has a visible label tied to it with for and id, so screen readers announce what to enter and a click on the label focuses the field.
  • Required fields carry the required attribute, so the browser explains a missing answer before anything is sent. Say “required” in words as well; an asterisk or a colour alone is easy to miss.
  • The spam trap field (_gotcha) is hidden from screen readers with aria-hidden and skipped by the Tab key, so people never meet it.
  • In the JavaScript versions, show the confirmation or error in an element with role="status" so the result is announced, and keep the entered answers when sending fails.

Changed the fields? Paste your version into the HTML form tester to see exactly what it sends, or run it through the GDPR form checker.

How the code talks to Formward

Each form you create gets its own endpoint in the form https://forms.formward.eu/f/your-form-id. The HTML version posts to it directly and the browser is redirected to a thank-you page, so it works without JavaScript.

The Next.js version below sends the same fields with fetch and an Accept: application/json header. Formward then answers with { ok: true, id }, or an error body with 402 when the plan limit is reached and 429 when the rate limit kicks in. See responses and status codes.

Next.js client component

"use client";

import { useState } from "react";

export function ClientFeedbackFormForm() {
  const [sent, setSent] = useState(false);

  async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const form = e.currentTarget;
    const res = await fetch("https://forms.formward.eu/f/your-form-id", {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(form),
    });
    if (res.ok) {
      setSent(true);
      form.reset();
    }
  }

  if (sent) return <p>Thanks! Your message has been sent.</p>;

  return (
    <form onSubmit={onSubmit}>
      <label htmlFor="name">Name</label>
      <input type="text" name="name" id="name" required />
      <label htmlFor="email">Email</label>
      <input type="email" name="email" id="email" required />
      <label htmlFor="project">Project</label>
      <input type="text" name="project" id="project" />
      <label htmlFor="rating">Overall rating</label>
      <select name="rating" id="rating">
        <option value="Excellent">Excellent</option>
        <option value="Good">Good</option>
        <option value="Average">Average</option>
        <option value="Poor">Poor</option>
      </select>
      <label htmlFor="feedback">Your feedback</label>
      <textarea name="feedback" id="feedback" required />
      <input
        type="text"
        name="_gotcha"
        tabIndex={-1}
        autoComplete="off"
        style={{ position: "absolute", left: "-9999px" }}
        aria-hidden="true"
      />
      <button type="submit">Send</button>
    </form>
  );
}

Spam protection

  • The generated code already includes the hidden _gotcha honeypot. Leave it in: a bot that fills it gets a normal success response, the submission is filed as spam and no email is sent.
  • Every form has a per-IP rate limit, and you can restrict it to your own domains with the allowed-origins list in the form settings.
  • Cloudflare Turnstile is optional and works on every plan, including Free. Turn it on in the form settings, add the widget to your markup and Formward checks the token server-side.
  • The form settings can also reject disposable email addresses, which is worth turning on when a fake address would waste your time.

What happens after submit

  • Each answer is emailed to you and stored in the EU on every plan.
  • From Personal, export the answers as CSV to compare ratings across projects.
  • From Professional, the autoresponder can thank the client straight away.

Questions

Can I use the answers as testimonials?
Only with the client's permission. Ask in a separate, unticked checkbox or by email, and quote them only if they say yes.
Should feedback be anonymous?
Anonymous answers are often more candid, but you cannot follow up. For client work a named form usually works better; for staff feedback, use the anonymous template.

Customize before publishing

  • Remove fields you do not need and mark only essential answers as required.
  • Replace placeholder wording with terms your audience already understands.
  • Add your privacy notice, retention details and expected response time.
  • Test keyboard focus, validation errors and the confirmation state on mobile.

Use this template

Create a free account and the form is set up from this template. Copy your endpoint and replace https://forms.formward.eu/f/your-form-id in the code above.

Use this template →