Thomas Kim
Back to Posts
Jan 8, 2025
3 min read

Modern Form Validation Techniques

Form validation is crucial for data integrity and user experience. Let’s explore modern approaches to building robust, user-friendly forms.

Client-Side Validation Benefits

Form Validation Example

Here’s a complete form validation implementation:

import { useState } from 'react' function ValidationForm() { const [formData, setFormData] = useState({ email: '', password: '', confirmPassword: '', username: '' }) const [errors, setErrors] = useState({}) const [touched, setTouched] = useState({}) const validateEmail = (email) => { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return re.test(email) } const validateField = (name, value) => { switch(name) { case 'email': return validateEmail(value) ? '' : 'Please enter a valid email' case 'password': return value.length >= 8 ? '' : 'Password must be at least 8 characters' case 'confirmPassword': return value === formData.password ? '' : 'Passwords do not match' case 'username': return value.length >= 3 ? '' : 'Username must be at least 3 characters' default: return '' } } const handleChange = (e) => { const { name, value } = e.target setFormData(prev => ({ ...prev, [name]: value })) if (touched[name]) { setErrors(prev => ({ ...prev, [name]: validateField(name, value) })) } } const handleBlur = (e) => { const { name, value } = e.target setTouched(prev => ({ ...prev, [name]: true })) setErrors(prev => ({ ...prev, [name]: validateField(name, value) })) } const handleSubmit = (e) => { e.preventDefault() const newErrors = {} Object.keys(formData).forEach(key => { const error = validateField(key, formData[key]) if (error) newErrors[key] = error }) if (Object.keys(newErrors).length === 0) { console.log('Form submitted successfully!', formData) } else { setErrors(newErrors) } } return ( <form onSubmit={handleSubmit}> <div> <label>Username</label> <input type="text" name="username" value={formData.username} onChange={handleChange} onBlur={handleBlur} /> {errors.username && touched.username && ( <span className="error">{errors.username}</span> )} </div> <div> <label>Email</label> <input type="email" name="email" value={formData.email} onChange={handleChange} onBlur={handleBlur} /> {errors.email && touched.email && ( <span className="error">{errors.email}</span> )} </div> <button type="submit">Submit</button> </form> ) }

Validation Patterns

Email Validation

function validateEmail(email) { const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return regex.test(email) }

Password Strength

function validatePassword(password) { const hasLength = password.length >= 8 const hasUpperCase = /[A-Z]/.test(password) const hasLowerCase = /[a-z]/.test(password) const hasNumber = /\d/.test(password) const hasSpecialChar = /[!@#$%^&*]/.test(password) return { isValid: hasLength && hasUpperCase && hasLowerCase && hasNumber, strength: [hasLength, hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar] .filter(Boolean).length } }

Form Libraries

For complex forms, consider these libraries:

React Hook Form

import { useForm } from 'react-hook-form' function MyForm() { const { register, handleSubmit, formState: { errors } } = useForm() const onSubmit = (data) => { console.log(data) } return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('email', { required: 'Email is required', pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email address' } })} /> {errors.email && <span>{errors.email.message}</span>} <button type="submit">Submit</button> </form> ) }

Formik + Yup

import { Formik, Form, Field } from 'formik' import * as Yup from 'yup' const validationSchema = Yup.object({ email: Yup.string() .email('Invalid email') .required('Required'), password: Yup.string() .min(8, 'Must be at least 8 characters') .required('Required') }) function MyForm() { return ( <Formik initialValues={{ email: '', password: '' }} validationSchema={validationSchema} onSubmit={(values) => console.log(values)} > {({ errors, touched }) => ( <Form> <Field name="email" type="email" /> {errors.email && touched.email && <div>{errors.email}</div>} <button type="submit">Submit</button> </Form> )} </Formik> ) }

Best Practices

  1. Validate on blur - Don’t annoy users with errors while typing
  2. Show success states - Positive feedback improves UX
  3. Clear error messages - Tell users exactly what’s wrong
  4. Disable submit on invalid - Prevent unnecessary submissions
  5. Always validate server-side - Never trust client-side validation alone

Conclusion

Good form validation enhances user experience and data quality. Start with native HTML5 validation, then enhance with JavaScript for complex scenarios!

Related

© 2025 Thomas Kim