A Net Promoter Score (NPS) collection widget with a 0-10 numeric selector, optional follow-up textarea, and a submit callback. Designed for in-app feedback collection. Builds on the existing Rating component’s interaction patterns while using a numeric scale instead of stars.
Introduction
Overview
NPS is a standard customer satisfaction metric. This widget provides a consistent, accessible 0-10 selector with an optional freeform feedback field and a submit action. The widget is presentation-only; score storage and analysis are consumer responsibilities.
Goals
0-10 numeric selector with clear visual states (detractor, passive, promoter).
Optional follow-up textarea for qualitative feedback.
Submit callback returning the score and optional comment.
Compact footprint suitable for embedding in sidebars, modals, or bottom sheets.
Ship Storybook stories covering all states.
Non-Goals
Score persistence or analytics dashboards.
Multi-question surveys (see In-App Survey widget).
Email-based NPS collection.
Score calculation or aggregation.
Scope
In Scope
Item
Description
NpsWidget component
0-10 selector, optional textarea, submit button
Score categories
Visual indication of detractor (0-6), passive (7-8), promoter (9-10)
Follow-up textarea
Optional freeform feedback field shown after score selection
Submit action
Calls onSubmit({ score, comment }) callback
Thank-you state
Confirmation message after submission
Storybook stories
Default, WithComment, Submitted, Inline, Compact
Out of Scope
Item
Rationale
Score storage
Consumer handles via callback
Analytics
Separate concern
CSAT or CES variants
Different scales; separate widgets if needed
Users and Pain Points
User
Pain Point
Product teams
No standard NPS component; teams build one-off implementations
UX researchers
Inconsistent NPS presentation leads to unreliable data
End users
Unclear scoring UI or missing feedback opportunity
Definitions
Term
Definition
NPS
Net Promoter Score, a customer loyalty metric on a 0-10 scale
Detractor
Score 0-6, indicating dissatisfaction
Passive
Score 7-8, indicating neutral satisfaction
Promoter
Score 9-10, indicating high satisfaction
Current State
rating.tsx provides a star-based rating input (1-N scale) with controlled/uncontrolled modes and keyboard navigation. No 0-10 numeric NPS selector exists. Products use ad-hoc implementations with inconsistent scales and labeling.
Proposed Solution
Create an NpsWidget at src/components/widgets/nps-widget.tsx that:
Renders 11 numbered buttons (0-10) in a horizontal row.
Colors buttons by category: detractor (warm/red), passive (neutral/yellow), promoter (positive/green) using design tokens.
Optionally shows a textarea after score selection for follow-up comments.
Provides a submit button that calls onSubmit({ score, comment }).
Transitions to a thank-you confirmation state after submission.
Supports labels at scale endpoints (“Not likely” / “Extremely likely”).
Requirements
The widget must be accessible via keyboard, support both inline and popover placement, and not persist any state internally.
Functional Requirements
ID
Requirement
Priority
FR-01
Render 11 buttons labeled 0 through 10
Must
FR-02
Highlight the selected score with active styling
Must
FR-03
Display endpoint labels (“Not at all likely” at 0, “Extremely likely” at 10)
Must
FR-04
Optionally show a textarea for comments after score selection
Should
FR-05
Render a submit button; call onSubmit({ score, comment }) on click
Must
FR-06
Transition to a thank-you state after successful submission
Must
FR-07
Support a configurable question prompt (default: “How likely are you to recommend us?”)
Should
FR-08
Color score buttons by category (detractor/passive/promoter)
Should
FR-09
Support a compact variant with smaller buttons for narrow spaces
Should
FR-10
Support a loading state on the submit button during async submission
Should
Non-Functional Requirements
ID
Requirement
NFR-01
Bundle size under 2 KB gzipped
NFR-02
Full light/dark theme support
NFR-03
Score selection responds within one frame (no animation delay on tap)
API / Interface Requirements
interface NpsSubmission {
score:number;
comment?:string;
}
interface NpsWidgetProps {
question?:string; // default "How likely are you to recommend us to a friend or colleague?"
showComment?:boolean; // default true
commentPlaceholder?:string; // default "Tell us more (optional)"
submitLabel?:string; // default "Submit"
thankYouMessage?:string; // default "Thank you for your feedback!"