Simple Form

intermediate
25 min

Explorer

1
⚛️
SimpleForm.jsx

Click files to view code →

React Simple Form with Validation Tutorial

1. What is the Question and What to Achieve Here

Build a form component with multiple input fields that includes real-time validation, error messages, and form submission handling. The form should validate user input and provide feedback before submission.

[!TIP] Goal

  • Create a multi-field form (name, email, password, etc.)
  • Implement real-time field validation
  • Display error messages for invalid inputs
  • Handle form submission
  • Prevent submission with invalid data
  • Show success/error states after submission
  • Make form accessible

2. How to Solve

Use React's

text
useState
hook to manage form field values and validation errors. Create validation functions for each field type. Use controlled components where React state drives the input values. Validate on blur and/or onChange events.

3. What Are the Things That Need to Be Gathered

[!IMPORTANT] Requirements

  • React with hooks
  • Understanding of:
    • Controlled components
    • Form events (onChange, onBlur, onSubmit)
    • Input validation techniques
    • Regular expressions for email, etc.
    • Error state management
    • Form submission handling

No external dependencies needed for basic validation.

4. Key Topics to Consider and Plan of Action

Key Topics:

  • Controlled Components: Binding form inputs to React state
  • Validation Logic: Creating reusable validation functions
  • Error Handling: Displaying field-specific errors
  • Form Submission: Preventing default and handling data
  • User Experience: When to show errors (onBlur vs onChange)
  • Accessibility: Labels, error announcements, ARIA attributes

Plan of Action:

  1. Create
    text
    SimpleForm
    component
  2. Initialize state for form values and errors
  3. Create validation functions for each field
  4. Build controlled input components
  5. Add onChange handlers to update state
  6. Implement onBlur validation
  7. Create form submission handler
  8. Display error messages conditionally
  9. Add loading and success states
  10. Implement accessibility features

5. Code the Question

jsxShowing 50 of 381 lines
import React, { useState } from 'react';
import './SimpleForm.css';

function SimpleForm() {
  // Form data state
  const [formData, setFormData] = useState({
    fullName: '',
    email: '',
    password: '',
    confirmPassword: '',
    age: '',
    terms: false
  });

  // Error state
  const [errors, setErrors] = useState({});
  
  // Form submission state
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [submitSuccess, setSubmitSuccess] = useState(false);

  // Validation functions
  const validateName = (name) => {
    if (!name.trim()) {
      return 'Name is required';
    }
    if (name.trim().length < 2) {
      return 'Name must be at least 2 characters';
    }
    return '';
  };

  const validateEmail = (email) => {
    if (!email) {
      return 'Email is required';
    }
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      return 'Please enter a valid email address';
    }
    return '';
  };

  const validatePassword = (password) => {
    if (!password) {
      return 'Password is required';
    }
    if (password.length < 8) {
      return 'Password must be at least 8 characters';
    }
// ...

CSS Styling (SimpleForm.css):

cssShowing 50 of 136 lines
.form-container {
  max-width: 500px;
  margin: 2rem auto;
  padding: 2rem;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  font-family: Arial, sans-serif;
}

.form-container h2 {
  margin-top: 0;
  color: #333;
  text-align: center;
}

.simple-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.form-group {
  display: flex;
  flex-direction: column;
}

.form-group label {
  margin-bottom: 0.5rem;
  font-weight: 600;
  color: #333;
  font-size: 0.875rem;
}

.required {
  color: #f44336;
}

.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="password"],
.form-group input[type="number"] {
  padding: 0.75rem;
  font-size: 1rem;
  border: 2px solid #e0e0e0;
  border-radius: 6px;
  transition: border-color 0.2s ease;
  outline: none;
}

// ...

6. Things to Consider

Best Practices:

  • Validation Timing: Validate on blur for better UX, not on every keystroke
  • Clear Errors: Clear errors when user starts correcting them
  • Accessible Errors: Use aria-describedby and role="alert"
  • Prevent Default: Always call e.preventDefault() on form submission
  • Client + Server Validation: Never trust client-side validation alone
  • Loading States: Disable submit button during submission

Common Pitfalls:

  • Don't validate on every keystroke (annoying for users)
  • Don't forget to prevent form submission with errors
  • Don't trust client-side validation for security
  • Remember to handle async validation (e.g., checking if email exists)
  • Don't forget to reset form state after successful submission

Enhancements:

  • Async Validation: Check username/email availability with API
  • Password Strength Indicator: Visual strength meter
  • Show/Hide Password: Toggle password visibility
  • Auto-save: Save form progress to localStorage
  • Multi-step Forms: Break into multiple steps
  • Field Dependencies: Show/hide fields based on other values
  • Custom Validation Rules: Build reusable validator library
  • Internationalization: Support multiple languages

Advanced Version with Custom Hooks:

jsxShowing 50 of 65 lines
// useForm.js - Custom hook for form management
import { useState } from 'react';

export function useForm(initialValues, validationRules) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  const [touched, setTouched] = useState({});

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setValues(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value
    }));
  };

  const handleBlur = (e) => {
    const { name } = e.target;
    setTouched(prev => ({ ...prev, [name]: true }));
    
    if (validationRules[name]) {
      const error = validationRules[name](values[name], values);
      setErrors(prev => ({ ...prev, [name]: error }));
    }
  };

  const validateAll = () => {
    const newErrors = {};
    Object.keys(validationRules).forEach(key => {
      const error = validationRules[key](values[key], values);
      if (error) newErrors[key] = error;
    });
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const resetForm = () => {
    setValues(initialValues);
    setErrors({});
    setTouched({});
  };

  return {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    validateAll,
    resetForm
// ...

Testing Considerations:

  • Test each validation rule
  • Test form submission with valid data
  • Test form submission with invalid data
  • Test error display and clearing
  • Test all input types
  • Test accessibility with screen readers
  • Test keyboard navigation

Real-World Use Cases:

  • User registration forms
  • Login forms
  • Contact forms
  • Profile update forms
  • Checkout forms
  • Survey forms
  • Application forms

This form component demonstrates comprehensive form handling with validation and is production-ready for most use cases.

No files open

Click a file in the explorer to view