Contact
Feedback rating widget
Score first, then a comment box appears
Score first, then a comment box appears
Create a feedback widget with Tailwind CSS. Use a max-w-md bordered card with a heading asking how likely the person is to recommend the product, and a row of eleven small numbered buttons from zero to ten that wrap on narrow screens, with muted "Not likely" and "Very likely" labels at the ends. When a score is chosen it fills dark and a second stage appears: a short prompt whose wording depends on the score band, a textarea, an optional checkbox offering a follow-up conversation, and a dark submit button beside a ghost "Not now" link. Then add JavaScript that highlights the chosen number, reveals the second stage with a small height and opacity transition, changes the prompt for detractors, passives and promoters, keeps the score in a hidden field, and replaces the card contents with a short thank-you state on submit. <section class="mx-auto max-w-md px-6 py-14">
<div id="npsCard" class="rounded-2xl border border-neutral-200 bg-white p-7 shadow-sm">
<h2 class="text-base font-semibold text-neutral-900">How likely are you to recommend us to a colleague?</h2>
<div id="npsScale" class="mt-5 flex flex-wrap gap-1.5">
<button data-score="0" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">0</button>
<button data-score="1" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">1</button>
<button data-score="2" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">2</button>
<button data-score="3" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">3</button>
<button data-score="4" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">4</button>
<button data-score="5" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">5</button>
<button data-score="6" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">6</button>
<button data-score="7" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">7</button>
<button data-score="8" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">8</button>
<button data-score="9" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">9</button>
<button data-score="10" class="nps h-9 w-9 rounded-lg border border-neutral-200 text-sm text-neutral-600 transition hover:border-neutral-900">10</button>
</div>
<div class="mt-2 flex justify-between text-[11px] text-neutral-400">
<span>Not likely</span><span>Very likely</span>
</div>
<div id="npsStage" class="max-h-0 overflow-hidden opacity-0 transition-all duration-300">
<div class="pt-6">
<label id="npsPrompt" class="mb-2 block text-sm font-medium text-neutral-900">What is the main reason for your score?</label>
<textarea rows="4" placeholder="Anything at all — the specific beats the polite."
class="w-full resize-none rounded-xl border border-neutral-200 px-3.5 py-2.5 text-sm outline-none transition focus:border-neutral-900 focus:ring-4 focus:ring-neutral-900/10"></textarea>
<label class="mt-3 flex items-start gap-2.5 text-sm text-neutral-600">
<input type="checkbox" class="mt-0.5 rounded border-neutral-300" />
<span>Happy for someone to follow up about this.</span>
</label>
<div class="mt-5 flex items-center gap-3">
<button id="npsSubmit" class="rounded-xl bg-neutral-900 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-neutral-800">Send feedback</button>
<button class="text-sm text-neutral-500 underline-offset-4 hover:text-neutral-900 hover:underline">Not now</button>
</div>
</div>
</div>
<input id="npsValue" type="hidden" value="" />
</div>
</section> var card = document.getElementById("npsCard");
var buttons = Array.prototype.slice.call(document.querySelectorAll(".nps"));
var stage = document.getElementById("npsStage");
var prompt = document.getElementById("npsPrompt");
var hidden = document.getElementById("npsValue");
function promptFor(score) {
if (score <= 6) return "Sorry to hear it. What went wrong?";
if (score <= 8) return "What would have made that a 10?";
return "Glad to hear it. What works best for you?";
}
buttons.forEach(function (btn) {
btn.addEventListener("click", function () {
var score = Number(btn.dataset.score);
hidden.value = score;
buttons.forEach(function (b) {
var on = b === btn;
b.classList.toggle("bg-neutral-900", on);
b.classList.toggle("text-white", on);
b.classList.toggle("border-neutral-900", on);
b.classList.toggle("text-neutral-600", !on);
});
prompt.textContent = promptFor(score);
// A generous ceiling: the stage is short, and max-height only needs to clear it.
stage.classList.remove("max-h-0", "opacity-0");
stage.classList.add("max-h-96", "opacity-100");
});
});
document.getElementById("npsSubmit").addEventListener("click", function () {
card.innerHTML =
'<div class="py-6 text-center">' +
'<div class="mx-auto grid h-12 w-12 place-items-center rounded-full bg-green-100 text-xl text-green-700">✓</div>' +
'<p class="mt-4 text-base font-semibold text-neutral-900">Thank you — that is genuinely useful</p>' +
'<p class="mt-1.5 text-sm text-neutral-500">Every response is read by the product team on Monday morning.</p>' +
"</div>";
});