export function websiteFeedbackWidget(form: FormTs) {
// Website Feedback Widget
// Demonstrates: ThumbRating, EmojiRating, SuggestionChips, Dropdown, conditional visibility
// ============================================
// HEADER - Compact widget style
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Quick Feedback',
computedValue: () => 'Help us improve your experience',
customStyles: {
backgroundColor: '#0ea5e9',
color: 'white',
padding: '16px 20px',
borderRadius: '10px',
textAlign: 'center',
fontSize: '14px'
}
});
});
// ============================================
// SECTION 1: Quick Rating
// ============================================
const ratingSection = form.addSubform('rating', {
title: 'How is your experience?',
customStyles: () => {
const thumb = ratingSection.thumbRating('quickThumb')?.value();
if (thumb === 'up') return { backgroundColor: '#ecfdf5', padding: '16px', borderRadius: '8px' };
if (thumb === 'down') return { backgroundColor: '#fef2f2', padding: '16px', borderRadius: '8px' };
return {};
}
});
ratingSection.addRow(row => {
row.addThumbRating('quickThumb', {
label: 'Is this page helpful?',
showLabels: true,
upLabel: 'Yes',
downLabel: 'No',
size: 'lg',
alignment: 'center'
});
});
// ============================================
// SECTION 2: Positive Feedback Path
// ============================================
const positiveSection = form.addSubform('positive', {
title: 'Great to hear!',
isVisible: () => ratingSection.thumbRating('quickThumb')?.value() === 'up',
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px' }
});
positiveSection.addRow(row => {
row.addEmojiRating('satisfactionLevel', {
label: 'How satisfied are you overall?',
preset: 'satisfaction',
size: 'md',
alignment: 'center'
});
});
positiveSection.addRow(row => {
row.addSuggestionChips('whatWorked', {
label: 'What worked well for you?',
suggestions: [
{ id: 'easy-nav', name: 'Easy navigation' },
{ id: 'clear-info', name: 'Clear information' },
{ id: 'fast-load', name: 'Fast loading' },
{ id: 'good-design', name: 'Good design' },
{ id: 'helpful-content', name: 'Helpful content' },
{ id: 'mobile-friendly', name: 'Mobile friendly' }
],
max: 3,
alignment: 'center'
});
});
positiveSection.addSpacer({ height: '12px' });
positiveSection.addRow(row => {
row.addTextarea('positiveComment', {
label: 'Any other comments? (optional)',
placeholder: 'Tell us what you liked...',
rows: 2
});
});
// ============================================
// SECTION 3: Negative Feedback Path
// ============================================
const negativeSection = form.addSubform('negative', {
title: 'Sorry to hear that',
isVisible: () => ratingSection.thumbRating('quickThumb')?.value() === 'down',
customStyles: { backgroundColor: '#fef2f2', padding: '16px', borderRadius: '8px' }
});
negativeSection.addRow(row => {
row.addDropdown('issueType', {
label: 'What type of issue did you encounter?',
options: [
{ id: 'usability', name: 'Hard to use / confusing' },
{ id: 'content', name: 'Missing or unclear information' },
{ id: 'bug', name: 'Something is broken' },
{ id: 'slow', name: 'Page is too slow' },
{ id: 'design', name: 'Design / layout issues' },
{ id: 'mobile', name: 'Mobile experience problems' },
{ id: 'other', name: 'Other issue' }
],
placeholder: 'Select issue type...',
isRequired: () => ratingSection.thumbRating('quickThumb')?.value() === 'down'
});
});
negativeSection.addRow(row => {
row.addSuggestionChips('specificIssues', {
label: 'Select all that apply:',
suggestions: () => {
const issueType = negativeSection.dropdown('issueType')?.value();
switch (issueType) {
case 'usability':
return [
{ id: 'nav-confusing', name: 'Confusing navigation' },
{ id: 'hard-find', name: 'Hard to find things' },
{ id: 'too-many-clicks', name: 'Too many clicks' },
{ id: 'unclear-labels', name: 'Unclear labels' }
];
case 'content':
return [
{ id: 'outdated', name: 'Outdated info' },
{ id: 'incomplete', name: 'Incomplete' },
{ id: 'confusing-text', name: 'Confusing text' },
{ id: 'missing-details', name: 'Missing details' }
];
case 'bug':
return [
{ id: 'broken-link', name: 'Broken link' },
{ id: 'error-message', name: 'Error message' },
{ id: 'form-issue', name: 'Form not working' },
{ id: 'display-issue', name: 'Display problem' }
];
case 'slow':
return [
{ id: 'initial-load', name: 'Initial load' },
{ id: 'images', name: 'Images loading' },
{ id: 'interactions', name: 'Slow interactions' },
{ id: 'timeout', name: 'Timeouts' }
];
default:
return [
{ id: 'general-issue', name: 'General issue' },
{ id: 'frustrating', name: 'Frustrating experience' },
{ id: 'not-intuitive', name: 'Not intuitive' }
];
}
},
isVisible: () => negativeSection.dropdown('issueType')?.value() !== null,
alignment: 'left'
});
});
negativeSection.addSpacer({ height: '12px' });
negativeSection.addRow(row => {
row.addTextarea('issueDetails', {
label: 'Please describe the issue:',
placeholder: 'What were you trying to do? What happened?',
rows: 3,
isRequired: () => ratingSection.thumbRating('quickThumb')?.value() === 'down'
});
});
negativeSection.addRow(row => {
row.addRatingScale('urgency', {
label: 'How much did this impact your experience?',
preset: 'custom',
min: 1,
max: 5,
lowLabel: 'Minor annoyance',
highLabel: 'Major blocker',
size: 'sm',
alignment: 'center'
});
});
// ============================================
// SECTION 4: Suggestions (always visible after rating)
// ============================================
const suggestionSection = form.addSubform('suggestions', {
title: 'Suggestions',
isVisible: () => ratingSection.thumbRating('quickThumb')?.value() !== null
});
suggestionSection.addRow(row => {
row.addRadioButton('hasSuggestion', {
label: 'Do you have any suggestions for improvement?',
options: [
{ id: 'yes', name: 'Yes, I have ideas' },
{ id: 'no', name: 'No, just the feedback above' }
],
orientation: 'horizontal'
});
});
suggestionSection.addRow(row => {
row.addTextarea('suggestionText', {
label: 'Share your suggestion:',
placeholder: 'What would make this better for you?',
rows: 2,
isVisible: () => suggestionSection.radioButton('hasSuggestion')?.value() === 'yes'
});
});
// ============================================
// SECTION 5: Contact (Optional)
// ============================================
const contactSection = form.addSubform('contact', {
title: 'Follow Up',
isVisible: () => ratingSection.thumbRating('quickThumb')?.value() !== null
});
contactSection.addRow(row => {
row.addCheckbox('wantsResponse', {
label: 'I would like a response about my feedback'
});
});
contactSection.addRow(row => {
row.addEmail('email', {
label: 'Your email address',
placeholder: 'you@example.com',
isRequired: () => contactSection.checkbox('wantsResponse')?.value() === true,
isVisible: () => contactSection.checkbox('wantsResponse')?.value() === true
});
});
// ============================================
// SECTION 6: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Summary',
isVisible: () => {
const thumb = ratingSection.thumbRating('quickThumb')?.value();
if (thumb === 'up') return true;
if (thumb === 'down' && negativeSection.dropdown('issueType')?.value()) return true;
return false;
}
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const thumb = ratingSection.thumbRating('quickThumb')?.value();
const satisfaction = positiveSection.emojiRating('satisfactionLevel')?.value();
const whatWorked = positiveSection.suggestionChips('whatWorked')?.value() || [];
const issueType = negativeSection.dropdown('issueType')?.value();
const specificIssues = negativeSection.suggestionChips('specificIssues')?.value() || [];
const urgency = negativeSection.ratingScale('urgency')?.value();
const hasSuggestion = suggestionSection.radioButton('hasSuggestion')?.value();
const satisfactionLabels: Record<string, string> = {
'very-bad': 'Very Unsatisfied',
'bad': 'Unsatisfied',
'neutral': 'Neutral',
'good': 'Satisfied',
'excellent': 'Very Satisfied'
};
const issueLabels: Record<string, string> = {
'usability': 'Usability',
'content': 'Content',
'bug': 'Bug/Error',
'slow': 'Performance',
'design': 'Design',
'mobile': 'Mobile',
'other': 'Other'
};
let summary = '';
if (thumb === 'up') {
summary = 'Positive Feedback\n';
summary += '─'.repeat(20) + '\n\n';
if (satisfaction) {
summary += `Satisfaction: ${satisfactionLabels[satisfaction] || satisfaction}\n`;
}
if (whatWorked.length > 0) {
summary += `What worked: ${whatWorked.length} items\n`;
}
} else if (thumb === 'down') {
summary = 'Issue Report\n';
summary += '─'.repeat(20) + '\n\n';
if (issueType) {
summary += `Issue Type: ${issueLabels[issueType] || issueType}\n`;
}
if (specificIssues.length > 0) {
summary += `Specifics: ${specificIssues.length} selected\n`;
}
if (urgency) {
summary += `Impact: ${urgency}/5\n`;
}
}
if (hasSuggestion === 'yes') {
summary += '\n+ Suggestion included';
}
return summary || 'Awaiting feedback...';
},
customStyles: () => {
const thumb = ratingSection.thumbRating('quickThumb')?.value();
const baseStyles = {
padding: '12px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
};
if (thumb === 'up') {
return { ...baseStyles, backgroundColor: '#ecfdf5', borderLeft: '3px solid #10b981' };
}
return { ...baseStyles, backgroundColor: '#fef2f2', borderLeft: '3px solid #ef4444' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const thumb = ratingSection.thumbRating('quickThumb')?.value();
if (thumb === 'up') return 'Send Feedback';
if (thumb === 'down') return 'Report Issue';
return 'Submit';
},
isVisible: () => ratingSection.thumbRating('quickThumb')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank you!',
message: 'Your feedback helps us improve. We appreciate you taking the time to share your thoughts.'
});
}