From 8d09630a0d03b1f44e9bf5c99605430015c13b59 Mon Sep 17 00:00:00 2001 From: Federico Coppede Date: Fri, 27 Feb 2026 12:50:26 -0300 Subject: [PATCH] docs: update feedback form (#11717) This PR forces the user to enter a reason/explanation before submitting a negative feedback. Negative feedback without an explanation is not actionable. --- apps/docs/components/feedback.tsx | 82 +++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/apps/docs/components/feedback.tsx b/apps/docs/components/feedback.tsx index b2c2e586f..5c27404dd 100644 --- a/apps/docs/components/feedback.tsx +++ b/apps/docs/components/feedback.tsx @@ -1,20 +1,43 @@ 'use client'; -import { useState } from 'react'; +import { useState, FormEvent } from 'react'; import { mixpanelClient } from '@/utils/mixpanel'; import { usePathname } from 'next/navigation'; import { ThumbsUp, ThumbsDown } from 'lucide-react'; import { cn } from '@/utils/cn'; export function Feedback() { + const MAX_CHARS = 500; const pathname = usePathname(); const [voted, setVoted] = useState(null); + const [showReasonInput, setShowReasonInput] = useState(false); + const [reason, setReason] = useState(''); const handleVote = (useful: boolean) => { - setVoted(useful); + if (!useful) { + setShowReasonInput(true); + return; + } + + setVoted(true); mixpanelClient.track('helpfulness_vote', { path: pathname, - useful: useful, + useful: true, + }); + }; + + const handleSubmitNegativeFeedback = (e: FormEvent) => { + e.preventDefault(); + + if (!reason.trim()) return; + + setVoted(false); + setShowReasonInput(false); + + mixpanelClient.track('helpfulness_vote', { + path: pathname, + useful: false, + reason: reason.trim(), }); }; @@ -28,6 +51,57 @@ export function Feedback() { ); } + if (showReasonInput) { + return ( +
+ +
+