Examples
This page introduces real-world implementation examples and best practices using md2form v2.
Basic Usage Examples
Simple Contact Form
import { parseForm, isParsedDocument } from "md2form"
const contactFormMd = `
---
collectEmail: true
showProgressBar: false
responseReceipt: always
---
# Contact Us
Feel free to contact us.
## Customer Information
### Your Name
#type short_text
#placeholder "John Doe"
#required true
### Email Address
#type email
#placeholder "example@example.com"
#required true
### Phone Number
#type phone
#placeholder "123-456-7890"
## Contact Details
### Subject
#type short_text
#placeholder "Your inquiry subject"
#required true
### Message
#type long_text
#placeholder "Please provide details"
#maxLength 1000
#required true
`
const contactResult = parseForm(contactFormMd, { strict: true })
if (!isParsedDocument(contactResult)) {
console.error(contactResult.diagnostics)
} else {
console.log(contactResult.document)
}Event Registration Form
const eventFormMd = `
---
collectEmail: true
allowMultipleResponses: false
showProgressBar: true
limitResponses: 100
themeColor: "#4F46E5"
---
# IT Conference 2024 Registration
## Attendee Information
### Name
#type short_text
#placeholder "Enter your full name"
#required true
### Company
#type short_text
#placeholder "Acme Corp"
#required true
### Position
#type dropdown
#options "Engineer","Designer","Product Manager","Sales","Marketing","Executive","Other"
#required true
### Years of Experience
#type number
#min 0
#max 50
#placeholder "Years"
## Session Preferences
### Interested Tracks
#type checkbox
#options "AI/Machine Learning","Web Development","Mobile Apps","DevOps","UI/UX","Startups"
#minSelected 1
#maxSelected 3
### Networking Event
#type boolean
#onLabel "Yes, I'll attend"
#offLabel "No thanks"
#default false
`
const eventResult = parseForm(eventFormMd, { strict: true })
if (isParsedDocument(eventResult)) {
const eventForm = eventResult.document
console.log(eventForm.title)
}Complex Implementation Examples
Customer Satisfaction Survey
const surveyFormMd = `
---
collectEmail: false
allowMultipleResponses: false
showProgressBar: true
shuffleQuestions: true
themeColor: "#059669"
---
# Customer Satisfaction Survey
Thank you for using our service. Your feedback helps us improve.
## Basic Information
### Age Group
#type radio
#options "Under 20","20s","30s","40s","50s","60+"
### Frequency of Use
#type dropdown
#options "Weekly or more","2-3 times monthly","Once monthly","A few times yearly","First time"
## Satisfaction Ratings
### Overall Satisfaction
#type rating
#scale 5
#labels "Dissatisfied","Very Satisfied"
#required true
### Item Evaluations
#type likert
#statements "Product/Service Quality","Price Fairness","Staff Response","Store Environment","Ease of Use"
#scaleLabels "Very Poor","Poor","Average","Good","Excellent"
#requiredPerStatement true
### Areas for Improvement
#type checkbox
#options "Increase variety","Lower prices","Extend hours","Online services","Expand parking","Other"
#maxSelected 3
## Additional Feedback
### Comments
#type long_text
#placeholder "Feel free to share your thoughts"
#maxLength 500
### Recommendation Likelihood
How likely are you to recommend our service to friends?
#type scale
#min 0
#max 10
#minLabel "Not likely"
#maxLabel "Very likely"
`Job Application Form
const recruitmentFormMd = `
---
collectEmail: true
allowMultipleResponses: false
showProgressBar: true
responseReceipt: always
themeColor: "#DC2626"
---
# Software Engineer Application
## Basic Information
### Full Name
#type short_text
#placeholder "Full name"
#required true
### Date of Birth
#type date
#required true
### Current Address
#type long_text
#placeholder "City, State, Country"
#required true
### Phone Number
#type phone
#placeholder "123-456-7890"
#required true
### GitHub Profile
#type short_text
#placeholder "https://github.com/username"
## Experience & Skills
### Educational Background
#type dropdown
#options "High School","College","Technical School","Bachelor's","Master's","PhD","Other"
### Years of Programming Experience
#type number
#min 0
#max 50
#required true
### Languages & Technologies
#type checkbox
#options "JavaScript","TypeScript","Python","Java","Go","Rust","React","Vue.js","Angular","Node.js","Docker","Kubernetes","AWS","Other"
### Skill Assessment
Rate your proficiency in each area.
#type matrix
#rows "Frontend Development","Backend Development","Database Design","Infrastructure/DevOps","Project Management"
#columns "No Experience","Beginner","Intermediate","Advanced","Expert"
#cellType radio
#requiredPerRow true
## Motivation & About You
### Why You're Interested
#type long_text
#placeholder "Tell us why you want to join"
#maxLength 1000
#required true
### About Yourself
#type long_text
#placeholder "Share your strengths and interests"
#maxLength 1000
#required true
## Application Materials
### Resume
#type file_upload
#allowedTypes "pdf","docx"
#maxFiles 1
#maxSizeMB 5
#required true
### Work Experience
#type file_upload
#allowedTypes "pdf","docx"
#maxFiles 1
#maxSizeMB 5
### Portfolio
#type file_upload
#allowedTypes "pdf","zip"
#maxFiles 1
#maxSizeMB 10
`Type-Safe Implementation in TypeScript
import { parseForm, isParsedDocument } from "md2form"
import type { FormDocument, ShortText, RatingField, CheckboxField } from "md2form"
// Type-safe form processing
function processForm(markdown: string) {
const result = parseForm(markdown, { strict: true })
if (!isParsedDocument(result)) {
console.error("Parse errors:")
result.diagnostics
.filter((d) => d.severity === "error")
.forEach((d) => console.error(` ${d.code}: ${d.message}`))
return null
}
const form: FormDocument = result.document
// Get form information
console.log(`Form: ${form.title}`)
console.log(`Pages: ${form.pages.length}`)
// Process each page
form.pages.forEach((page, pageIndex) => {
console.log(`\n=== ${page.title || `Page ${pageIndex + 1}`} ===`)
page.elements.forEach((element) => {
// Type-based branching
switch (element.type) {
case "short_text": {
const shortText = element as ShortText
console.log(`Text Question: ${shortText.label}`)
if (shortText.required) console.log(" *Required")
break
}
case "rating": {
const rating = element as RatingField
console.log(`Rating Question: ${rating.label}`)
console.log(` Scale: ${rating.scale}-point`)
break
}
case "checkbox": {
const checkbox = element as CheckboxField
console.log(`Checkbox: ${checkbox.label}`)
console.log(` Options: ${(checkbox.options ?? []).length}`)
if (checkbox.maxSelected) console.log(` Max: ${checkbox.maxSelected}`)
break
}
default:
console.log(`Other: ${element.label} (${element.type})`)
}
})
})
return form
}Practical Best Practices
1. Form Settings Optimization
// Optimized frontmatter settings for different use cases
// For surveys
const surveySettings = `
---
collectEmail: false
allowMultipleResponses: false
showProgressBar: true
shuffleQuestions: true
responseReceipt: never
---`
// For customer registration
const registrationSettings = `
---
collectEmail: true
allowMultipleResponses: false
showProgressBar: true
responseReceipt: always
themeColor: "#3B82F6"
---`
// For event signup
const eventSettings = `
---
collectEmail: true
allowMultipleResponses: false
limitResponses: 100
showProgressBar: true
responseReceipt: whenRequested
themeColor: "#10B981"
---`2. Validation Strategy
// Form data validation
function validateFormStructure(form: FormDocument) {
const errors: string[] = []
// Check required elements
if (!form.title) {
errors.push("Form title is required")
}
if (form.pages.length === 0) {
errors.push("At least one page is required")
}
// Validate each page
form.pages.forEach((page, pageIndex) => {
if (page.elements.length === 0) {
errors.push(`Page ${pageIndex + 1} has no questions`)
}
// Check required questions
page.elements.forEach((element, elementIndex) => {
if (element.required && !element.label) {
errors.push(`Page ${pageIndex + 1} Question ${elementIndex + 1}: label required`)
}
})
})
return errors
}3. Form Data Export and Processing
// Save form to JSON file
import { writeFile } from "fs/promises"
import type { FormDocument } from "md2form"
async function saveFormToFile(form: FormDocument, filename: string) {
try {
const jsonString = JSON.stringify(form, null, 2)
await writeFile(filename, jsonString, "utf-8")
console.log(`Form saved to ${filename}`)
} catch (error) {
console.error("Save error:", error)
}
}
// Get form statistics
import type { FormDocument } from "md2form"
function getFormStatistics(form: FormDocument) {
let totalQuestions = 0
let requiredQuestions = 0
const questionTypes: Record<string, number> = {}
form.pages.forEach((page) => {
page.elements.forEach((element) => {
totalQuestions++
if (element.required) {
requiredQuestions++
}
questionTypes[element.type] = (questionTypes[element.type] || 0) + 1
})
})
return {
pages: form.pages.length,
totalQuestions,
requiredQuestions,
questionTypes,
settings: form.settings,
}
}4. Batch Processing Multiple Forms
import { readdir, readFile } from "fs/promises"
import path from "path"
import { createParser } from "md2form"
// Process all Markdown forms in a directory
async function processFormsInDirectory(directoryPath: string) {
const parser = createParser({ strict: true })
const files = await readdir(directoryPath)
const mdFiles = files.filter((file) => path.extname(file) === ".md")
const results = []
for (const file of mdFiles) {
const filePath = path.join(directoryPath, file)
const markdown = await readFile(filePath, "utf-8")
const result = parser.parse(markdown)
if (result.ok) {
const stats = getFormStatistics(result.document)
results.push({ filename: file, success: true, form: result.document, stats })
console.log(`✅ ${file}: ${stats.totalQuestions} questions processed`)
} else {
const errors = result.diagnostics.filter((d) => d.severity === "error").map((d) => d.message)
results.push({ filename: file, success: false, errors })
console.error(`❌ ${file}: ${errors.join(", ")}`)
}
}
return results
}Web Application Integration
Express.js Integration
import express from "express"
import { parseForm } from "md2form"
const app = express()
app.use(express.json())
app.post("/api/forms/parse", (req, res) => {
const { markdown } = req.body
if (!markdown) {
return res.status(400).json({ error: "Markdown content is required" })
}
const result = parseForm(markdown, { strict: true, validateSettings: true })
if (!result.ok) {
return res.status(400).json({
success: false,
diagnostics: result.diagnostics.filter((d) => d.severity === "error"),
})
}
const stats = getFormStatistics(result.document)
res.json({ success: true, form: result.document, statistics: stats })
})Next.js Integration
// pages/api/forms/parse.ts
import type { NextApiRequest, NextApiResponse } from "next"
import { parseForm, isParsedDocument } from "md2form"
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" })
}
const { markdown } = req.body
const result = parseForm(markdown, { strict: true })
if (!isParsedDocument(result)) {
return res.status(400).json({
success: false,
diagnostics: result.diagnostics,
})
}
res.status(200).json({ success: true, data: result.document })
}Error Handling with Diagnostics
In v2, diagnostics are used instead of exceptions for error reporting.
import { parseForm } from "md2form"
import type { Diagnostic } from "md2form"
function robustFormParsing(markdown: string) {
if (!markdown.trim()) {
return { success: false, error: "Markdown content is empty" }
}
const result = parseForm(markdown, { strict: true, validateSettings: true })
const errors = result.diagnostics.filter((d) => d.severity === "error")
const warnings = result.diagnostics.filter((d) => d.severity === "warning")
if (errors.length > 0) {
return {
success: false,
errors: errors.map((d) => `${d.code}: ${d.message}`),
}
}
return {
success: true,
form: result.document,
warnings: warnings.map((d) => `${d.code}: ${d.message}`),
}
}Performance Optimization
createParser constructs the internal Markdown processor once, making it advantageous for batch processing.
import { createParser } from "md2form"
import type { FormDocument } from "md2form"
// Parallel processing with parser reuse
function processFormsInParallel(markdownFiles: string[]): FormDocument[] {
const parser = createParser({ strict: false })
return markdownFiles
.map((md) => parser.parse(md))
.filter((r) => r.ok)
.map((r) => r.document)
}Testing Best Practices
// Test example using bun test / Jest
import { parseForm, isParsedDocument } from "md2form"
import type { FormDocument } from "md2form"
describe("md2form parser tests", () => {
test("basic form parsing", () => {
const markdown = `
# Test Form
## Section1
### Question1
#type short_text
#required true
`
const result = parseForm(markdown, { strict: true })
expect(result.ok).toBe(true)
expect(result.document.title).toBe("Test Form")
expect(result.document.pages).toHaveLength(1)
expect(result.document.pages[0].elements).toHaveLength(1)
expect(result.document.pages[0].elements[0].type).toBe("short_text")
expect(result.document.pages[0].elements[0].label).toBe("Question1") // v2: label
expect(result.document.pages[0].elements[0].required).toBe(true)
})
test("frontmatter processing", () => {
const markdown = `
---
collectEmail: true
showProgressBar: true
---
# Test Form
## Section
### Question
#type short_text
`
const result = parseForm(markdown, { strict: true })
expect(result.ok).toBe(true)
expect(result.document.settings?.collectEmail).toBe(true)
expect(result.document.settings?.showProgressBar).toBe(true)
})
test("validation error detection", () => {
// radio without #options = MISSING_REQUIRED_FIELD error
const markdown = `
# Form
## Section
### Selection
#type radio
`
const result = parseForm(markdown, { strict: true })
expect(result.ok).toBe(false)
expect(result.diagnostics.some((d) => d.code === "MISSING_REQUIRED_FIELD")).toBe(true)
})
})Next Steps
Use these examples as reference to check the following pages for more detailed information:
- Type Definitions - Detailed TypeScript type definitions
- API Reference - Details of functions and types
Summary
md2form v2 is a library combining synchronous parsing, structured diagnostics, and type safety. Build your optimal form processing system using parseForm + isParsedDocument as the foundation, referencing the implementation examples on this page.