Turnkey Survey Modals
CsatModal, NpsModal, and CesModal — two-prop wrappers around SurveyModal + QuestionRating with built-in scoring categories.
CsatModal, NpsModal, and CesModal collapse the common "show a one-question survey" flow into a single import and two required props: question and onSubmit. Each composes the existing SurveyModal + QuestionRating primitives — no new focus-trap, escape-key, or storage code — and ships its own selected-value state plus a Submit/Skip pair.
These components still require an ancestor <SurveysProvider> because the underlying
SurveyModal calls useSurvey(surveyId). The wrappers remove primitive imports, not the provider
requirement.
Import
import { CsatModal, NpsModal, CesModal } from '@tour-kit/surveys';CsatModal
A 1–5 rating modal. onSubmit receives the raw rating.
<CsatModal
question="How easy was checkout?"
onSubmit={(rating) => track('csat', rating)}
/>Prop
Type
NpsModal
A 0–10 rating modal. onSubmit receives the score and a derived NpsCategory ('promoter' | 'passive' | 'detractor').
<NpsModal
question="How likely are you to recommend us?"
onSubmit={(score, category) => track('nps', { score, category })}
/>The category is computed by the pure helper computeNpsCategory(score):
| Score | Category |
|---|---|
| 9 – 10 | 'promoter' |
| 7 – 8 | 'passive' |
| 0 – 6 | 'detractor' |
Prop
Type
CesModal
A 1–7 rating modal. onSubmit receives the score and a derived CesCategory ('easy' | 'neutral' | 'difficult').
<CesModal
question="How easy was that?"
onSubmit={(score, category) => track('ces', { score, category })}
/>The category is computed by the pure helper computeCesCategory(score):
| Score | Category |
|---|---|
| 5 – 7 | 'easy' |
| 4 | 'neutral' |
| 1 – 3 | 'difficult' |
Prop
Type
Behaviour shared across all three
- Internal selected-value state is a transient
React.useState<number | null>. Submit is disabled until a rating is picked. - The modal closes automatically after Submit or Skip; supply
open+onOpenChangefor fully controlled state. - Reduced motion is inherited from
SurveyModalvia themotion-safe:Tailwind prefix — no extra setup required. - Each modal is tree-shakeable: importing only
CsatModaldoes not pullNpsModalorCesModal.
Props
All three share the same base — they extend SurveyModalProps (excluding surveyId, children, onSubmit, onSelect) and add their own submit signature.
interface CsatModalProps extends Omit<SurveyModalProps, 'surveyId' | 'children' | 'onSubmit' | 'onSelect'> {
surveyId?: string; // defaults to React.useId()
question: string;
ratingScale?: RatingScale; // default: 1–5 numeric
lowLabel?: string;
highLabel?: string;
onSubmit: (rating: number) => void;
onSkip?: () => void;
}
interface NpsModalProps extends Omit<SurveyModalProps, 'surveyId' | 'children' | 'onSubmit' | 'onSelect'> {
surveyId?: string;
question: string;
ratingScale?: RatingScale; // default: 0–10
lowLabel?: string;
highLabel?: string;
onSubmit: (score: number, category: NpsCategory) => void;
onSkip?: () => void;
}
interface CesModalProps extends Omit<SurveyModalProps, 'surveyId' | 'children' | 'onSubmit' | 'onSelect'> {
surveyId?: string;
question: string;
ratingScale?: RatingScale; // default: 1–7
lowLabel?: string;
highLabel?: string;
onSubmit: (score: number, category: CesCategory) => void;
onSkip?: () => void;
}Related
- SurveyModal — the underlying primitive each turnkey wraps.
- QuestionRating — the rating scale used inside each modal.
- useSurvey — provider hook called by
SurveyModal.
Ship onboarding, not config.
npm i @tour-kit/core is MIT and free. The Pro packages work unlicensed too — a one-time $99 license removes the production watermark when you ship.
MIT-licensed — no signup, no credit card. Pay once, only when you ship.