Skip to content

FRD-065: In-App Survey Widget

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

Document Summary

A lightweight in-app survey widget supporting radio, checkbox, and freeform text answer types. Displays 1-3 questions in either a modal or inline variant. Designed for quick contextual feedback collection without leaving the current page.


Introduction

Overview

Product teams need to collect targeted user feedback at specific moments (post-action, post-session, feature evaluation). A full survey tool is overkill; this widget provides a 1-3 question micro-survey that can be embedded inline or shown as a modal overlay.

Goals

  • Support radio (single-select), checkbox (multi-select), and text (freeform) answer types.
  • Allow 1-3 questions per survey instance.
  • Provide modal and inline display variants.
  • Submit all answers via a single callback.
  • Ship Storybook stories covering all question types and variants.

Non-Goals

  • Complex survey logic (branching, skip logic, piping).
  • Survey builder or admin UI.
  • Response storage or analytics.
  • More than 3 questions (use a dedicated survey tool for longer surveys).

Scope

In Scope

ItemDescription
InAppSurvey componentRenders questions with answer inputs and submit action
Question typesRadio (single-select), checkbox (multi-select), text (freeform)
Modal variantSurvey displayed in a dialog overlay
Inline variantSurvey rendered inline within the page content
Submit actionCalls onSubmit(answers) with all responses
Storybook storiesSingleRadio, MultiCheckbox, TextOnly, Mixed, Modal, Inline

Out of Scope

ItemRationale
Branching logicAdds significant complexity; out of scope for micro-surveys
Survey builderAdmin tooling is a separate product concern
Response analyticsConsumer responsibility
More than 3 questionsMicro-survey pattern; longer surveys use dedicated tools

Users and Pain Points

UserPain Point
Product managersNo quick way to collect contextual feedback without third-party tools
DevelopersIntegrating third-party survey SDKs for simple 1-2 question surveys
End usersDisruptive full-page surveys when only a quick question is needed

Definitions

TermDefinition
Micro-surveyA short survey (1-3 questions) designed for in-context feedback
Radio questionSingle-select from a list of options
Checkbox questionMulti-select from a list of options
Text questionFreeform text input for open-ended responses

Current State

No in-app survey widget exists. The NPS widget (FRD-064) handles the specific NPS use case. For general micro-surveys, products either use third-party tools (Pendo, Hotjar) or build custom forms. No reusable pattern exists in the design system.


Proposed Solution

Create an InAppSurvey widget at src/components/widgets/in-app-survey.tsx that:

  1. Accepts an array of SurveyQuestion objects (1-3 items).
  2. Renders each question with the appropriate input type (radio group, checkbox group, or textarea).
  3. Provides modal and inline variants via a variant prop.
  4. Collects answers in local state and submits all at once via onSubmit.
  5. Shows a thank-you/confirmation state after submission.
  6. Supports a dismiss action for the modal variant.

Requirements

The widget must validate that at least required questions are answered before enabling submit. It must be fully controlled for visibility (modal variant) and delegate all response handling to the consumer.


Functional Requirements

IDRequirementPriority
FR-01Render 1-3 questions based on the questions arrayMust
FR-02Support radio answer type with configurable optionsMust
FR-03Support checkbox answer type with configurable optionsMust
FR-04Support text answer type with configurable placeholderMust
FR-05Mark questions as required or optionalMust
FR-06Disable submit until all required questions are answeredMust
FR-07Call onSubmit(answers) with a map of question ID to answer value(s)Must
FR-08Show a thank-you state after submissionMust
FR-09Support variant: "modal" rendering inside a DialogMust
FR-10Support variant: "inline" rendering within page flowMust
FR-11Modal variant supports dismiss via onDismiss callbackMust
FR-12Support a survey title and optional descriptionShould

Non-Functional Requirements

IDRequirement
NFR-01Bundle size under 3 KB gzipped
NFR-02Full light/dark theme support
NFR-03Renders within one frame; no lazy loading needed for 1-3 questions

API / Interface Requirements

interface SurveyOption {
value: string;
label: string;
}
interface SurveyQuestion {
id: string;
type: "radio" | "checkbox" | "text";
prompt: string;
options?: SurveyOption[]; // required for radio and checkbox
placeholder?: string; // for text type
required?: boolean; // default true
}
type SurveyAnswers = Record<string, string | string[]>;
interface InAppSurveyProps {
questions: SurveyQuestion[]; // 1-3 items
title?: string;
description?: string;
variant?: "modal" | "inline"; // default "inline"
open?: boolean; // for modal variant
onOpenChange?: (open: boolean) => void;
submitLabel?: string; // default "Submit"
thankYouMessage?: string; // default "Thanks for your feedback!"
onSubmit: (answers: SurveyAnswers) => void | Promise<void>;
onDismiss?: () => void;
className?: string;
}

Accessibility Requirements

IDRequirement
A11Y-01Radio groups use role="radiogroup" with aria-labelledby pointing to the question prompt
A11Y-02Checkbox groups use role="group" with aria-labelledby
A11Y-03Text inputs have visible labels matching the question prompt
A11Y-04Required questions are indicated with aria-required="true"
A11Y-05Modal variant follows WAI-ARIA dialog pattern with focus trap
A11Y-06Thank-you state announced via aria-live="polite"
A11Y-07Validation errors are associated with fields via aria-describedby

Content and Documentation Requirements

  • Storybook doc page with props, question configuration examples, and variant guidance.
  • Stories: SingleRadio, MultiCheckbox, TextOnly, MixedQuestions, ModalVariant, InlineVariant, Required, ThankYou.
  • JSDoc on all exported types.

Dependencies

DependencyTypeNotes
DialogInternalModal variant container
RadioGroupInternalRadio question type
CheckboxInternalCheckbox question type
TextareaInternalText question type
ButtonInternalSubmit and dismiss actions

Risks and Tradeoffs

RiskImpactMitigation
3-question limit too restrictiveProduct teams want longer surveysDocument the limit; recommend dedicated tools for 4+ questions
Mixed question types in one surveyVisual inconsistencyStandardize spacing and alignment across question types
Modal fatigueUsers dismiss without answeringRecommend inline variant for non-critical surveys

Open Questions

  1. Should the widget support an “other” option with a freeform text field for radio/checkbox types?
  2. Do we need a progress indicator for multi-question surveys?
  3. Should the modal variant support a “Remind me later” option?

Acceptance Criteria

  • Renders 1, 2, and 3 questions correctly with radio, checkbox, and text types.
  • Required validation prevents submission until all required fields are answered.
  • onSubmit receives correct answer map.
  • Modal variant opens, traps focus, and dismisses correctly.
  • Inline variant renders within page flow.
  • Thank-you state displays after submission.
  • All Storybook stories render without errors.
  • Passes axe accessibility audit with zero violations.
  • Unit tests cover each question type, required validation, submit, and both variants.

LLM Handoff Instructions

When implementing this FRD:

  1. Create src/components/widgets/in-app-survey.tsx.
  2. Use Dialog for modal variant; render directly for inline variant.
  3. Use RadioGroup, Checkbox, and Textarea from @/components/ui/ for answer inputs.
  4. Create src/components/widgets/in-app-survey.stories.tsx with all listed stories.
  5. Create src/components/widgets/in-app-survey.test.tsx.
  6. Enforce the 1-3 question limit with a runtime warning if exceeded.
  7. Answer state: use Record&lt;string, string | string[]&gt; — string for radio/text, string[] for checkbox.

Decision Log

DateDecisionRationale
2026-05-26Limit to 3 questionsMicro-survey pattern; longer surveys belong in dedicated tools
2026-05-26Both modal and inline variantsDifferent use cases: modal for interrupts, inline for contextual

Document History

DateVersionAuthorChanges
2026-05-260.1David HolmesInitial draft