ReactForm
Home/Tools/Survey Form

React Form with Survey Form

An NPS-style survey combines a numeric rating picker, free-text feedback, and a feature usage checkbox group into a single cohesive form. The key UX moment is the thank-you screen after submission that reflects the user's score back to them — this makes the submission feel acknowledged and personalised rather than generic.

ReactForm Team·May 2026·4 min read

The challenge

Survey forms require multiple distinct input types — rating scales, checkboxes, and textareas — all working together with a thank-you state after submission.

  • Displaying the NPS scale (1–10) as individual clickable buttons that highlight the selected score
  • Combining three different question types into a single submit action with one success state
  • Showing the submitted score on the thank-you screen requires keeping it in state
  • Making the button grid for ratings look good on both mobile and desktop

Working code example

Here is a complete, self-contained working example you can drop directly into any React project. It uses Tailwind CSS for styling and requires no external dependencies beyond React itself.

SurveyForm.jsx
import { useState } from 'react';

const FEATURES = ['Form Builder', 'Response Exports', 'Email Notifications', 'Conditional Logic', 'API Access'];

export default function SurveyForm() {
  const [score, setScore] = useState(null);
  const [feedback, setFeedback] = useState('');
  const [features, setFeatures] = useState([]);
  const [submitted, setSubmitted] = useState(false);

  const toggleFeature = (f) =>
    setFeatures((prev) => prev.includes(f) ? prev.filter((x) => x !== f) : [...prev, f]);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (score === null) { alert('Please select a score'); return; }
    setSubmitted(true);
  };

  if (submitted)
    return (
      <div className="max-w-sm mx-auto p-6 bg-white rounded-2xl shadow space-y-3 text-center">
        <div className={`text-5xl font-black ${score >= 9 ? 'text-green-500' : score >= 7 ? 'text-yellow-500' : 'text-red-500'}`}>
          {score}
        </div>
        <p className="font-semibold text-gray-800">Thank you for your feedback!</p>
        <p className="text-sm text-gray-500">
          {score >= 9 ? "We're thrilled you love it." : score >= 7 ? 'Good to know — we're always improving.' : 'We hear you. Your input helps us get better.'}
        </p>
        {features.length > 0 && (
          <p className="text-xs text-gray-400">Features you use: {features.join(', ')}</p>
        )}
      </div>
    );

  return (
    <form onSubmit={handleSubmit} className="max-w-sm mx-auto p-6 bg-white rounded-2xl shadow space-y-6">
      <h2 className="text-xl font-bold text-gray-800">Quick Survey</h2>

      <div>
        <p className="text-sm font-medium text-gray-700 mb-3">
          How likely are you to recommend us? <span className="text-red-400">*</span>
        </p>
        <div className="flex gap-1 flex-wrap">
          {Array.from({ length: 10 }, (_, i) => i + 1).map((n) => (
            <button key={n} type="button" onClick={() => setScore(n)}
              className={`w-9 h-9 rounded-lg text-sm font-semibold border transition ${
                score === n
                  ? 'bg-teal-600 border-teal-600 text-white'
                  : 'border-gray-300 text-gray-600 hover:border-teal-400 hover:text-teal-600'
              }`}>
              {n}
            </button>
          ))}
        </div>
        <div className="flex justify-between text-xs text-gray-400 mt-1 px-0.5">
          <span>Not likely</span><span>Very likely</span>
        </div>
      </div>

      <div>
        <p className="text-sm font-medium text-gray-700 mb-2">What could be better?</p>
        <textarea value={feedback} onChange={(e) => setFeedback(e.target.value)}
          rows={3} style={{ resize: 'none' }} placeholder="Share your thoughts…"
          className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-teal-500" />
      </div>

      <div>
        <p className="text-sm font-medium text-gray-700 mb-2">Which features do you use?</p>
        <div className="space-y-1.5">
          {FEATURES.map((f) => (
            <label key={f} className="flex items-center gap-2 cursor-pointer">
              <input type="checkbox" checked={features.includes(f)} onChange={() => toggleFeature(f)}
                className="w-4 h-4 accent-teal-600" />
              <span className="text-sm text-gray-700">{f}</span>
            </label>
          ))}
        </div>
      </div>

      <button type="submit"
        className="w-full bg-teal-600 text-white font-semibold py-2 rounded-lg hover:bg-teal-700 transition">
        Submit Survey
      </button>
    </form>
  );
}

How ReactForm.co helps

ReactForm's visual builder handles all of the above — survey form configuration, validation rules, state management, and responsive layout — without writing a single line of code. Drag fields onto the canvas, configure their properties in the sidebar, and get production-ready React output. You can publish the form and collect responses instantly, or export the JSX to drop into your own codebase.

Build this form visually

Frequently asked questions

How do I build a 1-10 NPS rating picker in React?

Generate an array of numbers 1–10 with Array.from({ length: 10 }, (_, i) => i + 1). Map over it to render a button for each number. Store the selected score in state with useState(null). Apply conditional classes to highlight the selected button and clear the highlight on the others.

How do I show a personalised thank-you screen after a survey?

Keep the submitted values in state — do not clear them on submission. When submitted is true, render the thank-you screen and reference the stored values directly. For an NPS survey, you can show different messages based on the score: detractors (1–6), passives (7–8), and promoters (9–10).

How do I validate that a required survey question is answered?

Check the state value in your handleSubmit function before setting submitted to true. For the rating picker, check score !== null. For a checkbox group, check features.length > 0. Show an alert or an inline error message and return early if validation fails. The survey should not submit until required questions are answered.

Related topics

Build this form visually — no code needed

ReactForm.co handles survey form fields, validation, conditional logic, and responsive layout automatically. Publish in minutes and collect responses for free.