Form Builder
The Form Builder skill automates the creation of fillable forms, surveys, questionnaires, and interactive documents. It handles various form types including registration forms, feedback surveys, applications, intake forms, and assessment tools. The skill supports multiple output formats (PDF with fillable fields, HTML forms, Google Forms integration) with validation rules, conditional logic, and data collection capabilities.
Generate professional forms with proper field types, validation, styling, and submission handling for any data collection need.
Core Workflows
Workflow 1: Create PDF Fillable Form
Purpose:
Generate a PDF with interactive fillable fields
Steps:
Define form structure and fields
Set field types (text, checkbox, radio, dropdown, date)
Add validation rules for each field
Configure field properties (required, maxLength, etc.)
Apply styling and layout
Add instructions and help text
Generate PDF with fillable fields
Test form functionality
Implementation:
const
{
PDFDocument
,
PDFTextField
,
PDFCheckBox
,
PDFDropdown
,
rgb
}
=
require
(
'pdf-lib'
)
;
const
fs
=
require
(
'fs'
)
;
async
function
createFillablePDFForm
(
formData
,
outputPath
)
{
const
pdfDoc
=
await
PDFDocument
.
create
(
)
;
const
page
=
pdfDoc
.
addPage
(
[
612
,
792
]
)
;
// Letter size
const
{
width
,
height
}
=
page
.
getSize
(
)
;
const
fontSize
=
11
;
const
labelFontSize
=
10
;
// Add title
page
.
drawText
(
formData
.
title
,
{
x
:
50
,
y
:
height
-
50
,
size
:
18
,
color
:
rgb
(
0.2
,
0.2
,
0.2
)
}
)
;
// Add instructions
if
(
formData
.
instructions
)
{
page
.
drawText
(
formData
.
instructions
,
{
x
:
50
,
y
:
height
-
80
,
size
:
10
,
color
:
rgb
(
0.4
,
0.4
,
0.4
)
,
maxWidth
:
width
-
100
}
)
;
}
let
currentY
=
height
-
120
;
// Add form fields
for
(
const
field
of
formData
.
fields
)
{
// Draw field label
page
.
drawText
(
field
.
label
+
(
field
.
required
?
' *'
:
''
)
,
{
x
:
50
,
y
:
currentY
,
size
:
labelFontSize
,
color
:
rgb
(
0
,
0
,
0
)
}
)
;
currentY
-=
25
;
// Create field based on type
switch
(
field
.
type
)
{
case
'text'
:
case
'email'
:
case
'number'
:
const
textField
=
pdfDoc
.
getForm
(
)
.
createTextField
(
field
.
name
)
;
textField
.
addToPage
(
page
,
{
x
:
50
,
y
:
currentY
,
width
:
300
,
height
:
20
,
borderColor
:
rgb
(
0.5
,
0.5
,
0.5
)
,
borderWidth
:
1
}
)
;
if
(
field
.
placeholder
)
{
textField
.
setText
(
field
.
placeholder
)
;
}
if
(
field
.
maxLength
)
{
textField
.
setMaxLength
(
field
.
maxLength
)
;
}
break
;
case
'textarea'
:
const
textArea
=
pdfDoc
.
getForm
(
)
.
createTextField
(
field
.
name
)
;
textArea
.
addToPage
(
page
,
{
x
:
50
,
y
:
currentY
-
40
,
width
:
500
,
height
:
60
,
borderColor
:
rgb
(
0.5
,
0.5
,
0.5
)
,
borderWidth
:
1
}
)
;
textArea
.
enableMultiline
(
)
;
currentY
-=
40
;
break
;
case
'checkbox'
:
field
.
options
.
forEach
(
(
option
,
index
)
=>
{
const
checkbox
=
pdfDoc
.
getForm
(
)
.
createCheckBox
(
${
field
.
name
}
_
${
index
}
)
;
checkbox
.
addToPage
(
page
,
{
x
:
50
,
y
:
currentY
-
(
index
*
20
)
,
width
:
12
,
height
:
12
,
borderColor
:
rgb
(
0.5
,
0.5
,
0.5
)
,
borderWidth
:
1
}
)
;
page
.
drawText
(
option
,
{
x
:
70
,
y
:
currentY
-
(
index
*
20
)
+
2
,
size
:
10
,
color
:
rgb
(
0
,
0
,
0
)
}
)
;
}
)
;
currentY
-=
field
.
options
.
length
*
20
;
break
;
case
'radio'
:
const
radioGroup
=
pdfDoc
.
getForm
(
)
.
createRadioGroup
(
field
.
name
)
;
field
.
options
.
forEach
(
(
option
,
index
)
=>
{
radioGroup
.
addOptionToPage
(
option
,
page
,
{
x
:
50
,
y
:
currentY
-
(
index
*
20
)
,
width
:
12
,
height
:
12
,
borderColor
:
rgb
(
0.5
,
0.5
,
0.5
)
,
borderWidth
:
1
}
)
;
page
.
drawText
(
option
,
{
x
:
70
,
y
:
currentY
-
(
index
*
20
)
+
2
,
size
:
10
,
color
:
rgb
(
0
,
0
,
0
)
}
)
;
}
)
;
currentY
-=
field
.
options
.
length
*
20
;
break
;
case
'dropdown'
:
const
dropdown
=
pdfDoc
.
getForm
(
)
.
createDropdown
(
field
.
name
)
;
dropdown
.
addOptions
(
field
.
options
)
;
dropdown
.
addToPage
(
page
,
{
x
:
50
,
y
:
currentY
,
width
:
200
,
height
:
20
,
borderColor
:
rgb
(
0.5
,
0.5
,
0.5
)
,
borderWidth
:
1
}
)
;
break
;
case
'date'
:
const
dateField
=
pdfDoc
.
getForm
(
)
.
createTextField
(
field
.
name
)
;
dateField
.
addToPage
(
page
,
{
x
:
50
,
y
:
currentY
,
width
:
150
,
height
:
20
,
borderColor
:
rgb
(
0.5
,
0.5
,
0.5
)
,
borderWidth
:
1
}
)
;
dateField
.
setText
(
'MM/DD/YYYY'
)
;
break
;
}
// Add help text if provided
if
(
field
.
helpText
)
{
page
.
drawText
(
field
.
helpText
,
{
x
:
370
,
y
:
currentY
+
5
,
size
:
8
,
color
:
rgb
(
0.6
,
0.6
,
0.6
)
,
maxWidth
:
200
}
)
;
}
currentY
-=
40
;
// Add new page if running out of space
if
(
currentY
<
100
)
{
const
newPage
=
pdfDoc
.
addPage
(
[
612
,
792
]
)
;
currentY
=
height
-
50
;
}
}
// Add submit button placeholder (text)
page
.
drawText
(
'Please save and email this completed form to: '
+
formData
.
submitEmail
,
{
x
:
50
,
y
:
50
,
size
:
9
,
color
:
rgb
(
0.3
,
0.3
,
0.3
)
}
)
;
const
pdfBytes
=
await
pdfDoc
.
save
(
)
;
fs
.
writeFileSync
(
outputPath
,
pdfBytes
)
;
return
outputPath
;
}
Workflow 2: Generate HTML Form
Purpose:
Create interactive HTML form with client-side validation
Steps:
Define form structure and fields
Generate HTML markup
Add CSS styling for professional appearance
Implement JavaScript validation
Handle form submission
Add accessibility features (ARIA labels, keyboard navigation)
Make responsive for mobile devices
Test across browsers
Implementation:
function
generateHTMLForm
(
formData
,
outputPath
)
{
const
html
=
`
${ formData . title }
${ formData . instructions ? `${ formData . instructions }
` : '' };
fs
.
writeFileSync
(
outputPath
,
html
,
'utf8'
)
;
return
outputPath
;
}
function
generateFieldHTML
(
field
)
{
const
requiredAttr
=
field
.
required
?
'required'
:
''
;
const
requiredLabel
=
field
.
required
?
'<span class="required">*</span>'
:
''
;
switch
(
field
.
type
)
{
case
'text'
:
case
'email'
:
case
'number'
:
case
'tel'
:
case
'date'
:
return
;
case
'textarea'
:
return
;
case
'select'
:
return
;
case
'checkbox'
:
return
;
case
'radio'
:
return
;
default
:
return
''
;
}
}
function
generateValidationScript
(
formData
)
{
return
const form = document.getElementById('mainForm');
const submitBtn = document.getElementById('submitBtn');
const successMessage = document.getElementById('successMessage');
// Validation rules
const validationRules = {
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
phone: /^[\d\s\-\(\)]+$/
};
// Real-time validation
form.addEventListener('input', (e) => {
validateField(e.target);
});
// Form submission
form.addEventListener('submit', async (e) => {
e.preventDefault();
// Validate all fields
let isValid = true;
const fields = form.querySelectorAll('input, textarea, select');
fields.forEach(field => {
if (!validateField(field)) {
isValid = false;
}
});
if (!isValid) {
return;
}
// Disable submit button
submitBtn.disabled = true;
submitBtn.textContent = 'Submitting...';
try {
// Collect form data
const formData = new FormData(form);
const data = Object.fromEntries(formData);
// Submit to server
${
formData
.
submitUrl
?
const response = await fetch('
${
formData
.
submitUrl
}
', {
method: '
${
formData
.
method
||
'POST'
}
',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (response.ok) {
successMessage.style.display = 'block';
form.reset();
} else {
alert('Submission failed. Please try again.');
}
:
// No submit URL - just show success
console.log('Form data:', data);
successMessage.style.display = 'block';
form.reset();
}
} catch (error) {
alert('An error occurred. Please try again.');
console.error(error);
} finally {
submitBtn.disabled = false;
submitBtn.textContent = 'Submit';
}
});
function validateField(field) {
const errorEl = document.getElementById(field.name + '-error');
if (!errorEl) return true;
let isValid = true;
let errorMessage = '';
// Required check
if (field.hasAttribute('required') && !field.value.trim()) {
isValid = false;
errorMessage = 'This field is required';
}
// Email validation
if (field.type === 'email' && field.value && !validationRules.email.test(field.value)) {
isValid = false;
errorMessage = 'Please enter a valid email address';
}
// Pattern validation
if (field.hasAttribute('pattern') && field.value) {
const pattern = new RegExp(field.getAttribute('pattern'));
if (!pattern.test(field.value)) {
isValid = false;
errorMessage = 'Please enter a valid value';
}
}
// Update UI
if (isValid) {
field.classList.remove('invalid');
errorEl.classList.remove('visible');
} else {
field.classList.add('invalid');
errorEl.textContent = errorMessage;
errorEl.classList.add('visible');
}
return isValid;
}
;
}
Workflow 3: Survey/Questionnaire Generator
Purpose:
Create comprehensive surveys with multiple question types and logic
Steps:
Define survey structure and sections
Add various question types (multiple choice, rating, text, etc.)
Implement conditional logic (skip patterns)
Add validation rules
Configure answer choices and scales
Design results collection and analysis
Generate survey in preferred format
Set up response tracking
Implementation:
async
function
generateSurvey
(
surveyData
,
outputPath
)
{
const
survey
=
{
title
:
surveyData
.
title
,
description
:
surveyData
.
description
,
sections
:
surveyData
.
sections
.
map
(
section
=>
(
{
title
:
section
.
title
,
questions
:
section
.
questions
.
map
(
(
q
,
idx
)
=>
(
{
id
:
q
${
section
.
id
}
_
${
idx
+
1
}
,
type
:
q
.
type
,
text
:
q
.
text
,
required
:
q
.
required
!==
false
,
options
:
q
.
options
,
validation
:
q
.
validation
,
conditionalLogic
:
q
.
conditionalLogic
}
)
)
}
)
)
,
settings
:
{
allowAnonymous
:
surveyData
.
allowAnonymous
!==
false
,
showProgress
:
surveyData
.
showProgress
!==
false
,
randomizeQuestions
:
surveyData
.
randomizeQuestions
||
false
,
allowMultipleSubmissions
:
surveyData
.
allowMultipleSubmissions
||
false
}
}
;
// Generate HTML survey
const
html
=
generateSurveyHTML
(
survey
)
;
fs
.
writeFileSync
(
outputPath
,
html
,
'utf8'
)
;
return
{
surveyPath
:
outputPath
,
questionCount
:
survey
.
sections
.
reduce
(
(
sum
,
s
)
=>
sum
+
s
.
questions
.
length
,
0
)
,
settings
:
survey
.
settings
}
;
}
function
generateSurveyHTML
(
survey
)
{
return
${ survey . title }
${ survey . description }
${ survey . settings . showProgress ? ` ` : '' };
}
function
generateQuestionHTML
(
question
)
{
const
requiredMark
=
question
.
required
?
'<span class="required-indicator">*</span>'
:
''
;
switch
(
question
.
type
)
{
case
'multipleChoice'
:
return
;
case
'rating'
:
const
scale
=
question
.
scale
||
5
;
return
;
case
'text'
:
return
;
case
'checkbox'
:
return
;
default
:
return
''
;
}
}
function
generateSurveyScript
(
survey
)
{
return
function selectRating(questionId, value) {
// Remove previous selection
const container = document.querySelector(`[data-question-id="\${questionId}"]`);
container.querySelectorAll('.rating-option').forEach(opt => {
opt.classList.remove('selected');
});
// Add new selection
event.target.classList.add('selected');
document.getElementById(questionId).value = value;
}
// Form submission
document.getElementById('surveyForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const responses = Object.fromEntries(formData);
console.log('Survey responses:', responses);
// Submit to server or save locally
alert('Thank you for completing the survey!');
e.target.reset();
});
// Progress tracking
${
survey
.
settings
.
showProgress
?
const
questions
=
document
.
querySelectorAll
(
'.question'
)
;
const
progressFill
=
document
.
getElementById
(
'progressFill'
)
;
document
.
addEventListener
(
'input'
,
updateProgress
)
;
function
updateProgress
(
)
{
let
answered
=
0
;
questions
.
forEach
(
q
=>
{
const
inputs
=
q
.
querySelectorAll
(
'input, textarea'
)
;
const
hasAnswer
=
Array
.
from
(
inputs
)
.
some
(
input
=>
{
if
(
input
.
type
===
'radio'
||
input
.
type
===
'checkbox'
)
{
return
input
.
checked
;
}
return
input
.
value
.
trim
(
)
!==
''
;
}
)
;
if
(
hasAnswer
)
answered
++
;
}
);
const progress = (answered / questions.length) * 100;
progressFill.style.width = progress + '%';
}
:
''
}
`
;
}
Workflow 4: Form Data Processing
Purpose:
Handle form submissions and process collected data
Steps:
Set up submission endpoint
Validate submitted data
Process and sanitize inputs
Store data in database or spreadsheet
Send confirmation email
Generate summary reports
Export data for analysis
Workflow 5: Multi-Page Form with Progress
Purpose:
Create long forms split into multiple pages with progress tracking
Steps:
Divide form into logical sections
Create page navigation
Implement progress bar
Save progress between pages
Add validation at each step
Allow going back to edit
Submit all data at the end
Quick Reference
Action
Command/Trigger
PDF fillable form
"create fillable PDF form"
HTML form
"generate HTML form with [fields]"
Survey
"build survey about [topic]"
Contact form
"create contact form"
Registration form
"make registration form"
Feedback form
"generate feedback survey"
Multi-step form
"create multi-page form"
Best Practices
Clear Labels:
Use descriptive, concise labels for all fields
Logical Grouping:
Group related fields together
Required Fields:
Clearly mark required fields with asterisks
Help Text:
Provide guidance for complex fields
Validation:
Implement both client-side and server-side validation
Error Messages:
Show clear, helpful error messages
Accessibility:
Include ARIA labels, keyboard navigation
Mobile Responsive:
Ensure forms work on all devices
Progress Indicators:
Show progress for long forms
Save Progress:
Allow users to save and resume
Confirmation:
Show success message after submission
Security:
Use CSRF protection, sanitize inputs
Common Patterns
Contact Form:
{
fields
:
[
{
name
:
'name'
,
type
:
'text'
,
label
:
'Full Name'
,
required
:
true
}
,
{
name
:
'email'
,
type
:
'email'
,
label
:
'Email'
,
required
:
true
}
,
{
name
:
'phone'
,
type
:
'tel'
,
label
:
'Phone Number'
}
,
{
name
:
'subject'
,
type
:
'text'
,
label
:
'Subject'
,
required
:
true
}
,
{
name
:
'message'
,
type
:
'textarea'
,
label
:
'Message'
,
required
:
true
}
]
}
Event Registration:
{
fields
:
[
{
name
:
'attendeeName'
,
type
:
'text'
,
required
:
true
}
,
{
name
:
'email'
,
type
:
'email'
,
required
:
true
}
,
{
name
:
'ticketType'
,
type
:
'select'
,
options
:
[
'General'
,
'VIP'
]
,
required
:
true
}
,
{
name
:
'dietaryRestrictions'
,
type
:
'checkbox'
,
options
:
[
'Vegetarian'
,
'Vegan'
,
'Gluten-Free'
]
}
,
{
name
:
'specialRequests'
,
type
:
'textarea'
}
]
}
Dependencies
Install required packages:
npm
install
pdf-lib
For PDF forms
npm install express
For form submission handling
npm install validator
For input validation
npm install nodemailer
For email confirmations
Error Handling Validation Errors: Show specific field-level errors Network Errors: Handle submission failures gracefully Data Loss: Auto-save progress to prevent data loss Browser Compatibility: Test across different browsers Advanced Features Conditional Logic: conditionalLogic : { showIf : { field : 'employment' , value : 'employed' } , hideIf : { field : 'student' , value : 'yes' } } File Upload: { name : 'resume' , type : 'file' , accept : '.pdf,.doc,.docx' , maxSize : 5242880 // 5MB } Auto-Save: setInterval ( ( ) => { const formData = new FormData ( form ) ; localStorage . setItem ( 'formDraft' , JSON . stringify ( Object . fromEntries ( formData ) ) ) ; } , 30000 ) ;