MyTechBlog

Modular Forms: Building Scalable Web Forms

September 12, 2025 • Jane Doe

Creating complex forms can quickly become a maintenance nightmare. By breaking a form down into reusable, self‑contained modules, you gain flexibility, readability, and testability. This post walks through the core concepts of modular forms and provides a live example using vanilla JavaScript and modern HTML.

Why Modular Forms?

Core Building Blocks

1. Form Field Component

<template id="field-template">
  <div class="field">
    <label><span class="label-text"></span></label>
    <input class="input" />
    <div class="error"></div>
  </div>
</template>

<script>
class FormField extends HTMLElement {
  constructor() {
    super();
    const template = document.getElementById('field-template');
    const clone = template.content.cloneNode(true);
    this.attachShadow({mode:'open'}).appendChild(clone);
  }
  connectedCallback() {
    const label = this.getAttribute('label') || '';
    const type = this.getAttribute('type') || 'text';
    this.shadowRoot.querySelector('.label-text').textContent = label;
    const input = this.shadowRoot.querySelector('.input');
    input.type = type;
    input.name = this.getAttribute('name') || '';
    input.required = this.hasAttribute('required');
    input.addEventListener('input', () => this.validate());
  }
  validate() {
    const input = this.shadowRoot.querySelector('.input');
    const errorDiv = this.shadowRoot.querySelector('.error');
    if (input.validity.valid) {
      errorDiv.textContent = '';
      this.dispatchEvent(new CustomEvent('field-valid', {detail:{name:input.name,value:input.value}}));
    } else {
      errorDiv.textContent = input.validationMessage;
    }
  }
}
customElements.define('form-field', FormField);
</script>

2. Form Container

<form id="contact-form">
  <form-field label="Name" name="name" required></form-field>
  <form-field label="Email" name="email" type="email" required></form-field>
  <form-field label="Message" name="message" type="textarea" required></form-field>
  <button type="submit">Send</button>
</form>

<script>
const form = document.getElementById('contact-form');
form.addEventListener('submit', e => {
  e.preventDefault();
  const formData = new FormData(form);
  console.log('Submitted', Object.fromEntries(formData));
  alert('Form submitted! Check console for data.');
});
</script>

Live Demo