Skip to content

FRD-064: NPS Widget

FieldValue
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
Target Releasev2.0.0 (P2)
T-Shirt SizeS
TypeWidget

Document Summary

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

ItemDescription
NpsWidget component0-10 selector, optional textarea, submit button
Score categoriesVisual indication of detractor (0-6), passive (7-8), promoter (9-10)
Follow-up textareaOptional freeform feedback field shown after score selection
Submit actionCalls onSubmit({ score, comment }) callback
Thank-you stateConfirmation message after submission
Storybook storiesDefault, WithComment, Submitted, Inline, Compact

Out of Scope

ItemRationale
Score storageConsumer handles via callback
AnalyticsSeparate concern
CSAT or CES variantsDifferent scales; separate widgets if needed

Users and Pain Points

UserPain Point
Product teamsNo standard NPS component; teams build one-off implementations
UX researchersInconsistent NPS presentation leads to unreliable data
End usersUnclear scoring UI or missing feedback opportunity

Definitions

TermDefinition
NPSNet Promoter Score, a customer loyalty metric on a 0-10 scale
DetractorScore 0-6, indicating dissatisfaction
PassiveScore 7-8, indicating neutral satisfaction
PromoterScore 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:

  1. Renders 11 numbered buttons (0-10) in a horizontal row.
  2. Colors buttons by category: detractor (warm/red), passive (neutral/yellow), promoter (positive/green) using design tokens.
  3. Optionally shows a textarea after score selection for follow-up comments.
  4. Provides a submit button that calls onSubmit({ score, comment }).
  5. Transitions to a thank-you confirmation state after submission.
  6. 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

IDRequirementPriority
FR-01Render 11 buttons labeled 0 through 10Must
FR-02Highlight the selected score with active stylingMust
FR-03Display endpoint labels (“Not at all likely” at 0, “Extremely likely” at 10)Must
FR-04Optionally show a textarea for comments after score selectionShould
FR-05Render a submit button; call onSubmit({ score, comment }) on clickMust
FR-06Transition to a thank-you state after successful submissionMust
FR-07Support a configurable question prompt (default: “How likely are you to recommend us?”)Should
FR-08Color score buttons by category (detractor/passive/promoter)Should
FR-09Support a compact variant with smaller buttons for narrow spacesShould
FR-10Support a loading state on the submit button during async submissionShould

Non-Functional Requirements

IDRequirement
NFR-01Bundle size under 2 KB gzipped
NFR-02Full light/dark theme support
NFR-03Score 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!"
compact?: boolean;
loading?: boolean;
onSubmit: (submission: NpsSubmission) => void | Promise<void>;
onDismiss?: () => void;
className?: string;
}

Accessibility Requirements

IDRequirement
A11Y-01Score buttons use role="radiogroup" with role="radio" per button
A11Y-02Each button has aria-label with score number and category (e.g., “6, detractor”)
A11Y-03Arrow keys navigate between score buttons
A11Y-04Textarea has a visible label or aria-label
A11Y-05Thank-you state is announced via aria-live="polite"
A11Y-06Submit button is disabled until a score is selected

Content and Documentation Requirements

  • Storybook doc page with props, usage examples, and NPS methodology context.
  • Stories: Default, WithComment, Submitted, Compact, Loading, CustomQuestion.
  • JSDoc on all exported types.

Dependencies

DependencyTypeNotes
ButtonInternalScore buttons and submit
TextareaInternalComment field
Design tokensInternalCategory colors (detractor/passive/promoter)

Risks and Tradeoffs

RiskImpactMitigation
11 buttons overflow on narrow screensLayout breaksUse flexbox wrap or compact variant for mobile
Category colors conflict with themeAccessibility issueUse semantic tokens; ensure 4.5:1 contrast in both themes
Users submit without commentLower feedback qualityShow comment field by default; make it visually inviting

Open Questions

  1. Should the widget support a “remind me later” option in addition to dismiss?
  2. Do we need animated transitions between score selection and comment/thank-you states?
  3. Should the category color scheme be configurable or fixed to NPS conventions?

Acceptance Criteria

  • 0-10 buttons render with correct labels and endpoint text.
  • Selecting a score highlights the button and optionally shows the textarea.
  • Submit calls onSubmit with the correct score and comment.
  • Thank-you state displays after submission.
  • Keyboard navigation works across all score buttons.
  • All Storybook stories render without errors.
  • Passes axe accessibility audit with zero violations.
  • Unit tests cover score selection, comment entry, submit, and thank-you transition.

LLM Handoff Instructions

When implementing this FRD:

  1. Create src/components/widgets/nps-widget.tsx.
  2. Reference rating.tsx for keyboard navigation patterns (arrow key handling, role="radiogroup").
  3. Use Button variants for score buttons; apply category colors via conditional classes.
  4. Create src/components/widgets/nps-widget.stories.tsx with all listed stories.
  5. Create src/components/widgets/nps-widget.test.tsx.
  6. Category color mapping: 0-6 = destructive/warm, 7-8 = warning/neutral, 9-10 = success/positive.
  7. Use cn() for class merging. No inline styles.

Decision Log

DateDecisionRationale
2026-05-260-10 numeric buttons, not a sliderButtons are more accessible and match NPS survey conventions
2026-05-26Thank-you state is built inAvoids the widget disappearing abruptly after submit

Document History

DateVersionAuthorChanges
2026-05-260.1David HolmesInitial draft