Skip to content
intermediatePhase 34 · DOM

Form Handling

Intercept form submissions, validate inputs, and manage form state with JavaScript.

45m
0 problems
Topic Progress0%

Form Events

Forms have specific events for handling user input.

Submit Event

const form = document.querySelector('form');

form.addEventListener('submit', (e) => {
  e.preventDefault(); // Prevent page reload
  
  // Get form data
  const formData = new FormData(form);
  const data = Object.fromEntries(formData);
  
  console.log(data); // { name: 'Alice', email: 'alice@example.com' }
  
  // Send to server
  fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
  });
});

Input Event

const input = document.querySelector('input');

// Fires on every value change
input.addEventListener('input', (e) => {
  console.log('Current value:', e.target.value);
  console.log('Selection start:', e.target.selectionStart);
});

// Fires when value changes and element loses focus
input.addEventListener('change', (e) => {
  console.log('Final value:', e.target.value);
});

Focus and Blur

const input = document.querySelector('input');

// When element receives focus
input.addEventListener('focus', () => {
  input.classList.add('focused');
});

// When element loses focus
input.addEventListener('blur', () => {
  input.classList.remove('focused');
  // Validate on blur
  validateInput(input);
});

Other Form Events

// Reset event
form.addEventListener('reset', () => {
  console.log('Form reset');
  clearErrors();
});

// Invalid event
input.addEventListener('invalid', (e) => {
  e.preventDefault(); // Prevent browser validation UI
  showError(input, 'Invalid value');
});

// Select event (text inputs)
input.addEventListener('select', () => {
  console.log('Text selected:', input.value.substring(
    input.selectionStart,
    input.selectionEnd
  ));
});

Real-time Validation

const emailInput = document.querySelector('input[type="email"]');

emailInput.addEventListener('input', (e) => {
  const email = e.target.value;
  const isValid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);
  
  emailInput.classList.toggle('valid', isValid);
  emailInput.classList.toggle('invalid', !isValid && email.length > 0);
  
  const errorEl = emailInput.nextElementSibling;
  if (!isValid && email.length > 0) {
    errorEl.textContent = 'Please enter a valid email';
    errorEl.style.display = 'block';
  } else {
    errorEl.style.display = 'none';
  }
});

FormData API

FormData provides an easy way to collect and send form data.

Creating FormData

// From form element
const form = document.querySelector('form');
const formData = new FormData(form);

// Manually
const formData = new FormData();
formData.append('name', 'Alice');
formData.append('email', 'alice@example.com');

// From another FormData
const copy = new FormData(formData);

FormData Methods

const formData = new FormData();

// Add data
formData.append('name', 'Alice');
formData.append('hobbies', 'reading');
formData.append('hobbies', 'gaming'); // Multiple values

// Set (replaces existing)
formData.set('name', 'Bob');

// Get values
console.log(formData.get('name')); // 'Bob'
console.log(formData.getAll('hobbies')); // ['reading', 'gaming']

// Check existence
console.log(formData.has('email')); // false

// Delete
formData.delete('hobbies');

// Iterate
for (const [key, value] of formData) {
  console.log(`${key}: ${value}`);
}

Sending FormData

const form = document.querySelector('form');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  
  const formData = new FormData(form);
  
  // Method 1: Fetch with FormData (auto sets Content-Type)
  const response = await fetch('/api/users', {
    method: 'POST',
    body: FormData // Browser sets Content-Type: multipart/form-data
  });
  
  // Method 2: Convert to JSON
  const data = Object.fromEntries(formData);
  const response2 = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
  });
  
  // Method 3: URL encoded
  const encoded = new URLSearchParams(formData);
  const response3 = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: encoded
  });
});

File Uploads

const form = document.querySelector('form');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  
  const formData = new FormData(form); // Automatically includes files
  
  // Add additional data
  formData.append('userId', '123');
  
  const response = await fetch('/api/upload', {
    method: 'POST',
    body: FormData // multipart/form-data
  });
});

// Access files
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (e) => {
  const files = e.target.files;
  console.log('Selected files:', files.length);
  
  for (const file of files) {
    console.log(file.name, file.size, file.type);
  }
});

Validation Patterns

Form validation ensures data integrity before submission.

HTML5 Validation

<form>
  <input type="email" required>
  <input type="text" minlength="3" maxlength="50">
  <input type="number" min="0" max="100">
  <input type="text" pattern="[A-Za-z]{3}">
  <button type="submit">Submit</button>
</form>

JavaScript Validation

const form = document.querySelector('form');

form.addEventListener('submit', (e) => {
  const errors = validateForm(form);
  
  if (Object.keys(errors).length > 0) {
    e.preventDefault();
    showErrors(errors);
    return;
  }
  
  // Submit form
});

function validateForm(form) {
  const errors = {};
  
  const name = form.querySelector('[name="name"]');
  if (name.value.length < 2) {
    errors.name = 'Name must be at least 2 characters';
  }
  
  const email = form.querySelector('[name="email"]');
  if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email.value)) {
    errors.email = 'Please enter a valid email';
  }
  
  const age = form.querySelector('[name="age"]');
  if (age.value < 18 || age.value > 120) {
    errors.age = 'Age must be between 18 and 120';
  }
  
  return errors;
}

function showErrors(errors) {
  // Clear previous errors
  document.querySelectorAll('.error').forEach(el => {
    el.classList.remove('error');
    el.nextElementSibling?.remove();
  });
  
  // Show new errors
  Object.entries(errors).forEach(([field, message]) => {
    const input = document.querySelector(`[name="${field}"]`);
    input.classList.add('error');
    
    const errorEl = document.createElement('span');
    errorEl.className = 'error-message';
    errorEl.textContent = message;
    input.after(errorEl);
  });
}

Real-time Validation

function setupValidation(form) {
  const inputs = form.querySelectorAll('input, select, textarea');
  
  inputs.forEach(input => {
    input.addEventListener('blur', () => {
      validateField(input);
    });
    
    input.addEventListener('input', () => {
      if (input.classList.contains('error')) {
        validateField(input);
      }
    });
  });
}

function validateField(input) {
  const rules = {
    required: (v) => v.length > 0 || 'This field is required',
    email: (v) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(v) || 'Invalid email',
    minLength: (min) => (v) => 
      v.length >= min || `Must be at least ${min} characters`
  };
  
  const validators = input.dataset;
  let error = null;
  
  if (validators.required && !rules.required(input.value)) {
    error = rules.required(input.value);
  } else if (validators.email && !rules.email(input.value)) {
    error = rules.email(input.value);
  } else if (validators.minLength) {
    error = rules.minLength(parseInt(validators.minLength))(input.value);
  }
  
  if (error) {
    input.classList.add('error');
    input.classList.remove('valid');
    showError(input, error);
  } else {
    input.classList.remove('error');
    input.classList.add('valid');
    hideError(input);
  }
  
  return !error;
}

Practice Problems

0/3solved
Build Form Handling Component

Create a reusable React component implementing Form Handling. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Form Handling Testing

Write unit and integration tests for Form Handling using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Form Handling Performance

Optimize Form Handling for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. How do you prevent a form from reloading the page?

Question 1 options

2. What's the difference between 'input' and 'change' events?

Question 2 options

3. How do you get form data as an object?

Question 3 options

4. What Content-Type does FormData use when sent with fetch?

Question 4 options

Flashcards

Question

How to prevent form submission?

Answer

e.preventDefault() in the submit event handler prevents the default page reload.

Question

What is FormData?

Answer

An API that collects form data as key-value pairs, supporting text and file inputs.

Question

input vs change event?

Answer

input fires on every value change. change fires when value changes and element loses focus.

Question

How to send form data as JSON?

Answer

Convert FormData to object: Object.fromEntries(new FormData(form)), then JSON.stringify().

Question

What is Form Handling?

Answer

Form Handling is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Always use preventDefault() on form submit
  • 2.FormData provides easy form data access
  • 3.input fires immediately, change fires on blur
  • 4.Validate on both submit and blur for good UX
  • 5.Use FormData for file uploads

Interview Tips

  • Show form submission handling with preventDefault()
  • Demonstrate FormData usage for data collection
  • Implement real-time validation with input and blur events
  • Explain how to handle file uploads with FormData

Cheat Sheet

Form Handling Cheat Sheet

Form Events

  • submit: Form submission (use preventDefault)
  • input: Every value change
  • change: Value change on blur
  • focus/blur: Focus state

FormData API

const data = new FormData(form);
data.get('name');
data.getAll('hobbies');
Object.fromEntries(data); // to object

Validation

  • Use HTML5 attributes (required, pattern, etc.)
  • Validate on submit and blur
  • Show errors inline

Sending Data

  • FormData: multipart/form-data
  • Object.fromEntries: JSON
  • URLSearchParams: URL encoded