Survey Components
CSAT5 (Customer Satisfaction Score, 5-Point Scale)
Surveys to ask users about their overall satisfaction.
Example questions:
- "How satisfied are you with our product?"
- "How would you rate your overall experience?"
- "How satisfied are you with our customer support?"
import { CSAT5Survey } from 'react-feedback-surveys';
import 'react-feedback-surveys/index.css';
<CSAT5Survey
scaleStyle="emoji"
question="How would you rate your satisfaction with our product?"
minLabel="Very unsatisfied"
maxLabel="Very satisfied"
responseType="text"
textQuestion="We'd love to hear your thoughts — what can we improve?"
textButtonSendLabel="Send"
textButtonSkipLabel="Skip"
thankYouMessage="Thanks for your feedback!"
onScoreSubmit={({ value }) => {/* ... */}}
onFeedbackSubmit={({ value, text }) => {/* ... */}}
/>scaleStyle: emoji | numbers | stars.
CSAT2 (Customer Satisfaction Score, 2-Point Scale)
Surveys to ask users about specific features or flows.
Example questions:
- "Was this search helpful?"
- "Did you find what you were looking for?"
- "Are you satisfied with the checkout process?"
import { CSAT2Survey } from 'react-feedback-surveys';
import 'react-feedback-surveys/index.css';
<CSAT2Survey
scaleStyle="thumbs"
question="Are you satisfied with the result?"
responseType="text"
textQuestion="We'd love to hear your thoughts — what can we improve?"
textButtonSendLabel="Send"
textButtonSkipLabel="Skip"
thankYouMessage="Thank you for your feedback!"
onScoreSubmit={({ value }) => {/* ... */}}
onFeedbackSubmit={({ value, text }) => {/* ... */}}
/>scaleStyle: emoji | thumbs.
NPS10 (Net Promoter Score, 0–10 Scale)
Surveys to ask users if they'd recommend your product.
Example questions:
- "How likely are you to recommend us to a friend or colleague?"
- "On a scale of 0-10, would you recommend our service?"
- "How likely are you to recommend this product to others?"
import { NPS10Survey } from 'react-feedback-surveys';
import 'react-feedback-surveys/index.css';
<NPS10Survey
scaleStyle="numbers"
question="How likely are you to recommend our product/service to a friend or colleague?"
minLabel="Very unlikely"
maxLabel="Very likely"
responseType="text"
textQuestion="We'd love to hear your thoughts — what can we improve?"
textButtonSendLabel="Send"
textButtonSkipLabel="Skip"
thankYouMessage="Thank you for your feedback!"
onScoreSubmit={({ value }) => {/* ... */}}
onFeedbackSubmit={({ value, text }) => {/* ... */}}
/>scaleStyle: numbers.
CES7 (Customer Effort Score, 7-Point Scale)
Surveys to ask users how easy it is to use your product.
Example questions:
- "How easy was it to complete your task?"
- "How much effort did it take to resolve your issue?"
- "How easy was it to sign up for an account?"
import { CES7Survey } from 'react-feedback-surveys';
import 'react-feedback-surveys/index.css';
<CES7Survey
scaleStyle="numbers"
question="How easy was it to complete your task?"
minLabel="Very difficult"
maxLabel="Very easy"
responseType="text"
textQuestion="We'd love to hear your thoughts — what can we improve?"
textButtonSendLabel="Send"
textButtonSkipLabel="Skip"
thankYouMessage="Thank you for your feedback!"
onScoreSubmit={({ value }) => {/* ... */}}
onFeedbackSubmit={({ value, text }) => {/* ... */}}
/>scaleStyle: numbers.
Layout Components
Popup
The <Popup> component wraps survey widgets in a fixed overlay that slides in from the screen edge. It includes positioning, animations, and a close button for easy dismissal.
Usage
import { Popup, CSAT5Survey } from 'react-feedback-surveys';
import 'react-feedback-surveys/index.css';
<Popup
animated
classNames={{
base: 'custom-popup-base',
content: 'custom-popup-content',
close: 'custom-popup-close'
}}
placement="bottomRight"
onClose={() => console.log('Closed')}
>
<CSAT5Survey
scaleStyle="stars"
question="How would you rate your satisfaction?"
onScoreSubmit={({ value }) => {/* ... */}}
/>
</Popup>Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
placement | 'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft' | - | 'bottomRight' | Position of the popup relative to the screen edges. |
animated | boolean | - | true | Enables a fade-in animation when the popup appears. |
className | string | - | - | Additional CSS class name for the popup container. |
classNames | { base?: string; content?: string; close?: string } | - | - | Optional class names for internal popup elements. |
children | React.ReactNode | - | - | Content to render inside the popup (typically a survey component). |
onClose | () => void | - | - | Callback fired when the close button is clicked. |
For more examples, check out the Storybook stories (e.g., CSAT5Survey.stories.tsx, CSAT2Survey.stories.tsx).
Surface
The <Surface> component is a basic container wrapper that provides consistent styling for survey content. It's used internally by the Popup component and can be used standalone to display surveys with a card-like appearance.
The Surface component provides:
- Background color with depth/elevation (box shadow)
- Rounded corners (controlled via
--ft-surface-radius) - Responsive padding that adapts to mobile devices
Usage
import { Surface, CSAT5Survey } from 'react-feedback-surveys';
import 'react-feedback-surveys/index.css';
<Surface className="custom-surface">
<CSAT5Survey
scaleStyle="stars"
question="How would you rate your satisfaction?"
onScoreSubmit={({ value }) => {/* ... */}}
/>
</Surface>Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
className | string | - | - | Additional CSS class name for the surface container. |
children | React.ReactNode | - | - | Content to render inside the surface. |
The Surface component uses the --ft-surface-padding, --ft-surface-padding-mobile, and --ft-surface-radius CSS variables for responsive padding and border radius.
Props
Most props are shared across all survey widgets. Each widget differs only in its scaleStyle values.
Shared Props
| Prop | Type | Required | Description |
|---|---|---|---|
classNames | ClassNamesConfig (see below) | - | Optional class names to target internal parts. |
dir | 'ltr' | 'rtl' | 'auto' | - | Text direction for RTL/LTR language support. |
question | string | required | Main survey question displayed on the first screen. |
minLabel | string | - | Left label for the scale. |
maxLabel | string | - | Right label for the scale. |
responseType | null | 'text' | 'choices' | - | Enables optional follow-up feedback. |
textQuestion | string | - | Follow-up question displayed when responseType is defined. |
textButtonSendLabel | string | - | Submit label for the feedback screen. |
textButtonSkipLabel | string | - | Skip label for the feedback screen. |
choiceOptions | string[] | null | - | Predefined choices (when responseType === 'choices'). |
thankYouMessage | string | required | Message shown after submission. |
collectContact | boolean | - | Enables an optional email collection step before the success screen. |
userId | string | - | Existing user identity. When provided, the email collection step is skipped. |
contactQuestion | string | - | Question shown on the email collection screen. |
contactSubtext | string | - | Descriptive text shown above the email input. |
contactButtonSendLabel | string | - | Submit label for the email collection screen. |
contactButtonSkipLabel | string | - | Skip label for the email collection screen. |
ClassNamesConfig Type
interface ClassNamesConfig {
base?: {
base?: string; // The outer widget container
head?: string; // Header row containing title and close button
title?: string; // The heading that shows main/feedback/success text
body?: string; // Main content region (rating scale, feedback form or success)
rating?: string; // Additional class applied when rating screen is active
feedback?: string; // Additional class applied when feedback screen is active
contact?: string; // Additional class applied when email collection screen is active
success?: string; // Additional class applied when success screen is active
close?: string; // Close button
};
scale?: {
base?: string; // Container around the scale style
list?: string; // Wrapper for the interactive items (emoji/stars/numbers)
button?: string; // Each clickable item in the scale
icon?: string; // Icon inside a scale button (emoji, stars)
score?: string; // Number inside a scale button (for numeric variants)
labels?: string; // Left/Right labels displayed under the scale
};
}Shared Events
| Prop | Type | Required | Description |
|---|---|---|---|
onScoreSubmit | (payload: ScorePayload) => void | Promise<void> | - | Fires immediately when a score is selected, before any follow-up feedback screen. Captures the raw rating. |
onFeedbackSubmit | (payload: FeedbackPayload) => void | Promise<void> | - | Fires when feedback is submitted. Includes the selected score and the user's text(s). |
onContactSubmit | (payload: ContactPayload) => void | Promise<void> | - | Fires when the respondent submits an email on the optional email collection screen. Not called when the step is skipped or not shown. |
Event Payload Types:
type ScorePayload = { value: number };
type FeedbackPayload = { value: number; text?: string | string[] };
type ContactPayload = { value?: number; text?: string | string[]; email: string };Event behavior
onScoreSubmit
Invoked immediately when the user selects a score on the rating scale — this callback runs before any optional follow-up screen is shown.
Use it to persist the rating instantly.
The actual value returned depends on the survey type:
- CSAT2:
0–1 - CSAT5:
1–5 - CES7:
1–7 - NPS10:
0–10
onFeedbackSubmit
Invoked when the user completes the follow-up step and submits their feedback (only applies when responseType is text or choices).
This callback provides both the original score and the user's input.
The feedback step is always optional: respondents can submit feedback or skip it via the textButtonSkipLabel button (or by submitting with empty input), and either action advances to the next screen. onFeedbackSubmit only fires when feedback text or choices are actually submitted; it is not called when the step is skipped.
Arguments:
value: number— the same score previously passed toonScoreSubmittext: string | string[]— depends onresponseType:text: a single text commentchoices: an array of selected options (may include a free-text comment if enabled)
Important You should listen to both
onScoreSubmitandonFeedbackSubmit. A user may select a score but abandon the follow-up screen (close the widget, navigate away, refresh, etc.). Handling both events ensures you capture at least the rating even when additional feedback is not provided — and still receive extended data when it is.
onContactSubmit
When collectContact is true and no userId is provided, an optional email collection screen is shown after the rating/feedback screens and before the success screen. This lets you "close the feedback loop" by capturing an email for a respondent whose identity isn't already known to the host app.
- If
userIdis provided, the step is skipped entirely — the widget assumes identity is already known. - The step is always optional: respondents can submit an email or skip it, and either action advances to the success screen.
onContactSubmitonly fires when the respondent actually submits an email; it is not called when the step is skipped or not shown.
Arguments:
value?: number— the selected rating, if any.text?: string | string[]— the submitted feedback text or choices, if any.email: string— the email address entered by the respondent.
<CSAT5Survey
scaleStyle="numbers"
question="How would you rate your satisfaction with our product?"
responseType="text"
textQuestion="We'd love to hear your thoughts — what can we improve?"
thankYouMessage="Thanks for your feedback!"
collectContact
userId={currentUser?.id}
contactQuestion="Mind sharing your email so we can follow up?"
contactButtonSendLabel="Submit"
contactButtonSkipLabel="Skip"
onScoreSubmit={({ value }) => {/* ... */}}
onFeedbackSubmit={({ value, text }) => {/* ... */}}
onContactSubmit={({ value, text, email }) => {/* attribute the feedback to this email */}}
/>Scale Style Options
Each survey type supports specific scale styles for displaying the rating interface:
CSAT2Survey
| Prop | Type | Required | Description |
|---|---|---|---|
scaleStyle | 'emoji' | 'thumbs' | required | Emoji mood scale style (happy/sad faces) or thumbs up/down emoji scale style. |
CSAT5Survey
| Prop | Type | Required | Description |
|---|---|---|---|
scaleStyle | 'emoji' | 'numbers' | 'stars' | required | Emoji scale style (5 emotion levels), numeric scale style (1–5), or star rating scale style (1–5 stars). |
CES7Survey
| Prop | Type | Required | Description |
|---|---|---|---|
scaleStyle | 'numbers' | required | Numeric scale style (1–7). |
NPS10Survey
| Prop | Type | Required | Description |
|---|---|---|---|
scaleStyle | 'numbers' | required | Numeric scale style (0–10). |
Note: The numeric ranges are defined by the widget (e.g., CSAT5 uses a 1–5 scale, NPS10 uses 0–10).
Demo
- Live demo: View Storybook
- Run locally:
npm run storybook
Credits
Emoji icons used in this package are from Sensa Emoji — thanks to the Sensa team for creating such a great set of expressive icons.