export function seanEllisTestSurvey(form: FormTs) {
// Sean Ellis PMF Test - The iconic Product-Market Fit survey
// Demonstrates: RadioButton, EmojiRating, StarRating, MatrixQuestion, Textarea, dynamic styling, computed values
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Product-Market Fit Survey',
computedValue: () => 'Help us understand how valuable our product is to you.',
customStyles: {
backgroundColor: '#7c3aed',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: User Context
// ============================================
const contextSection = form.addSubform('context', {
title: 'About Your Usage'
});
contextSection.addRow(row => {
row.addRadioButton('usageFrequency', {
label: 'How often do you use our product?',
options: [
{ id: 'daily', name: 'Daily' },
{ id: 'weekly', name: 'Several times a week' },
{ id: 'monthly', name: 'A few times a month' },
{ id: 'rarely', name: 'Less than once a month' }
],
orientation: 'vertical',
isRequired: true
});
});
contextSection.addRow(row => {
row.addDropdown('userRole', {
label: 'What best describes your role?',
placeholder: 'Select your role...',
options: [
{ id: 'founder', name: 'Founder / CEO' },
{ id: 'product', name: 'Product Manager' },
{ id: 'developer', name: 'Developer / Engineer' },
{ id: 'designer', name: 'Designer' },
{ id: 'marketer', name: 'Marketing / Growth' },
{ id: 'sales', name: 'Sales' },
{ id: 'support', name: 'Customer Support' },
{ id: 'other', name: 'Other' }
],
isRequired: true
});
});
// ============================================
// SECTION 2: The Sean Ellis Question (Core PMF)
// ============================================
const pmfSection = form.addSubform('pmfSection', {
title: 'The Key Question',
isVisible: () => contextSection.radioButton('usageFrequency')?.value() !== null,
customStyles: () => {
const answer = pmfSection.radioButton('disappointment')?.value();
if (answer === 'very') return { backgroundColor: '#d1fae5', padding: '20px', borderRadius: '12px', border: '2px solid #10b981' };
if (answer === 'somewhat') return { backgroundColor: '#fef3c7', padding: '20px', borderRadius: '12px', border: '2px solid #f59e0b' };
if (answer === 'not') return { backgroundColor: '#fee2e2', padding: '20px', borderRadius: '12px', border: '2px solid #ef4444' };
return { backgroundColor: '#f8fafc', padding: '20px', borderRadius: '12px', border: '2px dashed #cbd5e1' };
}
});
pmfSection.addRow(row => {
row.addRadioButton('disappointment', {
label: 'How would you feel if you could no longer use our product?',
options: [
{ id: 'very', name: 'Very disappointed' },
{ id: 'somewhat', name: 'Somewhat disappointed' },
{ id: 'not', name: 'Not disappointed' }
],
orientation: 'vertical',
isRequired: true
});
});
// PMF Score Indicator
pmfSection.addRow(row => {
row.addTextPanel('pmfIndicator', {
isVisible: () => pmfSection.radioButton('disappointment')?.value() !== null,
computedValue: () => {
const answer = pmfSection.radioButton('disappointment')?.value();
if (answer === 'very') return '🎯 Strong PMF Signal! Users who say "Very disappointed" indicate your product is a must-have.';
if (answer === 'somewhat') return '📈 Good potential. Understanding what would make you "very disappointed" helps us improve.';
if (answer === 'not') return '💡 Thanks for your honesty. We\'d love to learn what would make this more valuable for you.';
return '';
},
customStyles: () => {
const answer = pmfSection.radioButton('disappointment')?.value();
const baseStyles = { padding: '12px', borderRadius: '8px', fontSize: '14px', marginTop: '8px' };
if (answer === 'very') return { ...baseStyles, backgroundColor: '#ecfdf5', color: '#047857' };
if (answer === 'somewhat') return { ...baseStyles, backgroundColor: '#fffbeb', color: '#b45309' };
if (answer === 'not') return { ...baseStyles, backgroundColor: '#fef2f2', color: '#b91c1c' };
return baseStyles;
}
});
});
// ============================================
// SECTION 3: Follow-up for "Very Disappointed"
// ============================================
const promoterSection = form.addSubform('promoterSection', {
title: 'What Makes Us Special?',
isVisible: () => pmfSection.radioButton('disappointment')?.value() === 'very',
customStyles: { backgroundColor: '#ecfdf5', padding: '16px', borderRadius: '8px' }
});
promoterSection.addRow(row => {
row.addTextarea('mainBenefit', {
label: 'What is the primary benefit you get from our product?',
placeholder: 'Describe the #1 thing that makes our product valuable to you...',
rows: 3,
autoExpand: true,
isRequired: true
});
});
promoterSection.addRow(row => {
row.addSuggestionChips('valuePillars', {
label: 'Which of these benefits do you experience? (Select all that apply)',
suggestions: [
{ id: 'time', name: 'Saves time' },
{ id: 'money', name: 'Saves money' },
{ id: 'quality', name: 'Better quality work' },
{ id: 'insights', name: 'Better insights' },
{ id: 'collaboration', name: 'Easier collaboration' },
{ id: 'automation', name: 'Automation' },
{ id: 'simplicity', name: 'Simplicity' },
{ id: 'reliability', name: 'Reliability' }
],
alignment: 'left'
});
});
promoterSection.addSpacer();
promoterSection.addRow(row => {
row.addTextarea('whoWouldMiss', {
label: 'What type of person/company would benefit most from our product?',
placeholder: 'Describe who you would recommend this to...',
rows: 2,
autoExpand: true
});
});
// ============================================
// SECTION 4: Follow-up for "Somewhat Disappointed"
// ============================================
const passiveSection = form.addSubform('passiveSection', {
title: 'Help Us Improve',
isVisible: () => pmfSection.radioButton('disappointment')?.value() === 'somewhat',
customStyles: { backgroundColor: '#fffbeb', padding: '16px', borderRadius: '8px' }
});
passiveSection.addRow(row => {
row.addTextarea('whatWouldMakeVery', {
label: 'What would need to change for you to be "very disappointed" without our product?',
placeholder: 'What features, improvements, or changes would make this a must-have for you?',
rows: 3,
autoExpand: true,
isRequired: true
});
});
passiveSection.addRow(row => {
row.addSuggestionChips('missingFeatures', {
label: 'What areas need improvement?',
suggestions: [
{ id: 'features', name: 'Missing features' },
{ id: 'performance', name: 'Speed/Performance' },
{ id: 'usability', name: 'Ease of use' },
{ id: 'integrations', name: 'Integrations' },
{ id: 'pricing', name: 'Pricing' },
{ id: 'support', name: 'Customer support' },
{ id: 'reliability', name: 'Reliability' },
{ id: 'mobile', name: 'Mobile experience' }
],
alignment: 'left'
});
});
passiveSection.addSpacer();
passiveSection.addRow(row => {
row.addTextarea('alternatives', {
label: 'What would you use instead if our product didn\'t exist?',
placeholder: 'Other tools, manual processes, or workarounds...',
rows: 2,
autoExpand: true
});
});
// ============================================
// SECTION 5: Follow-up for "Not Disappointed"
// ============================================
const detractorSection = form.addSubform('detractorSection', {
title: 'We Want to Understand',
isVisible: () => pmfSection.radioButton('disappointment')?.value() === 'not',
customStyles: { backgroundColor: '#fef2f2', padding: '16px', borderRadius: '8px' }
});
detractorSection.addRow(row => {
row.addRadioButton('whyNotDisappointed', {
label: 'Why wouldn\'t you be disappointed?',
options: [
{ id: 'alternatives', name: 'I have good alternatives' },
{ id: 'not-solving', name: 'It\'s not solving a real problem for me' },
{ id: 'early', name: 'I haven\'t used it enough yet' },
{ id: 'not-fit', name: 'It\'s not the right fit for my needs' },
{ id: 'other', name: 'Other reason' }
],
orientation: 'vertical',
isRequired: true
});
});
detractorSection.addRow(row => {
row.addTextarea('whatWouldHelp', {
label: 'What would make our product valuable to you?',
placeholder: 'What problem would we need to solve for you?',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 6: Overall Experience (All Respondents)
// ============================================
const experienceSection = form.addSubform('experience', {
title: 'Quick Rating',
isVisible: () => pmfSection.radioButton('disappointment')?.value() !== null
});
experienceSection.addRow(row => {
row.addStarRating('overallRating', {
label: 'How would you rate your overall experience with our product?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
experienceSection.addRow(row => {
row.addMatrixQuestion('productAspects', {
label: 'Rate these aspects of our product:',
rows: [
{ id: 'usefulness', label: 'Usefulness', isRequired: true },
{ id: 'easeOfUse', label: 'Ease of use', isRequired: true },
{ id: 'reliability', label: 'Reliability', isRequired: true },
{ id: 'value', label: 'Value for money' }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
striped: true
});
});
// ============================================
// SECTION 7: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Your Feedback Summary',
isVisible: () => pmfSection.radioButton('disappointment')?.value() !== null && experienceSection.starRating('overallRating')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const disappointment = pmfSection.radioButton('disappointment')?.value();
const rating = experienceSection.starRating('overallRating')?.value();
const frequency = contextSection.radioButton('usageFrequency')?.value();
const role = contextSection.dropdown('userRole')?.value();
const valuePillars = promoterSection.suggestionChips('valuePillars')?.value() || [];
const missingFeatures = passiveSection.suggestionChips('missingFeatures')?.value() || [];
if (!disappointment) return '';
let emoji = '🎯';
let pmfLabel = 'Strong PMF';
if (disappointment === 'somewhat') { emoji = '📈'; pmfLabel = 'Potential PMF'; }
if (disappointment === 'not') { emoji = '💭'; pmfLabel = 'Needs Work'; }
const frequencyLabels: Record<string, string> = {
'daily': 'Daily user',
'weekly': 'Weekly user',
'monthly': 'Monthly user',
'rarely': 'Occasional user'
};
let summary = `${emoji} PMF Survey Summary\n`;
summary += `${'═'.repeat(30)}\n\n`;
summary += `📊 PMF Signal: ${pmfLabel}\n`;
summary += `💫 Response: ${disappointment === 'very' ? 'Very disappointed' : disappointment === 'somewhat' ? 'Somewhat disappointed' : 'Not disappointed'}\n`;
if (rating) {
summary += `⭐ Rating: ${rating}/5 stars\n`;
}
if (frequency) {
summary += `📅 Usage: ${frequencyLabels[frequency] || frequency}\n`;
}
if (valuePillars.length > 0) {
summary += `\n✨ Key benefits: ${valuePillars.length} selected`;
}
if (missingFeatures.length > 0) {
summary += `\n⚠️ Improvement areas: ${missingFeatures.length} identified`;
}
return summary;
},
customStyles: () => {
const disappointment = pmfSection.radioButton('disappointment')?.value();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (disappointment === 'very') {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (disappointment === 'somewhat') {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
} else if (disappointment === 'not') {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return baseStyles;
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit PMF Survey',
isVisible: () => pmfSection.radioButton('disappointment')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You!',
message: 'Your feedback is incredibly valuable for understanding our product-market fit. We read every response and use this data to build a product that truly serves your needs.'
});
}