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:

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.