Form validation is a critical aspect of web applications that ensures users submit accurate, secure, and properly formatted data. React's component-based architecture offers several approaches to implementing robust form validation.
Form validation serves multiple purposes:
The simplest form of validation leverages HTML5 attributes:
1function SimpleValidatedForm() { 2 return ( 3 <form> 4 <input 5 type="email" 6 required 7 minLength={5} 8 placeholder="Enter your email" 9 /> 10 <input 11 type="password" 12 required 13 minLength={8} 14 placeholder="Enter your password" 15 /> 16 <button type="submit">Submit</button> 17 </form> 18 ); 19}
HTML5 attributes like required
, minLength
, pattern
, and type="email"
provide basic validation with minimal code. However, they offer limited customization and inconsistent browser implementations.
For more control, implement validation logic using React state:
1import React, { useState } from "react"; 2 3function CustomValidatedForm() { 4 const [email, setEmail] = useState(""); 5 const [password, setPassword] = useState(""); 6 const [errors, setErrors] = useState({}); 7 8 const validateForm = () => { 9 const newErrors = {}; 10 11 // Email validation 12 if (!email) { 13 newErrors.email = "Email is required"; 14 } else if (!/\S+@\S+\.\S+/.test(email)) { 15 newErrors.email = "Email is invalid"; 16 } 17 18 // Password validation 19 if (!password) { 20 newErrors.password = "Password is required"; 21 } else if (password.length < 8) { 22 newErrors.password = "Password must be at least 8 characters"; 23 } 24 25 setErrors(newErrors); 26 return Object.keys(newErrors).length === 0; 27 }; 28 29 const handleSubmit = (e) => { 30 e.preventDefault(); 31 if (validateForm()) { 32 console.log("Form submitted successfully"); 33 // Submit form data 34 } 35 }; 36 37 return ( 38 <form onSubmit={handleSubmit}> 39 <div> 40 <label>Email:</label> 41 <input 42 type="email" 43 value={email} 44 onChange={(e) => setEmail(e.target.value)} 45 /> 46 {errors.email && <p className="error">{errors.email}</p>} 47 </div> 48 49 <div> 50 <label>Password:</label> 51 <input 52 type="password" 53 value={password} 54 onChange={(e) => setPassword(e.target.value)} 55 /> 56 {errors.password && <p className="error">{errors.password}</p>} 57 </div> 58 59 <button type="submit">Submit</button> 60 </form> 61 ); 62}
This approach provides complete control over validation logic and error messages but requires more code for complex forms.
For a better user experience, validate inputs as users type or when they blur from a field:
1function RealtimeValidatedInput() { 2 const [value, setValue] = useState(""); 3 const [error, setError] = useState(""); 4 const [touched, setTouched] = useState(false); 5 6 const validate = (val) => { 7 if (!val) { 8 return "This field is required"; 9 } 10 return ""; 11 }; 12 13 const handleChange = (e) => { 14 const newValue = e.target.value; 15 setValue(newValue); 16 if (touched) { 17 setError(validate(newValue)); 18 } 19 }; 20 21 const handleBlur = () => { 22 setTouched(true); 23 setError(validate(value)); 24 }; 25 26 return ( 27 <div> 28 <input 29 type="text" 30 value={value} 31 onChange={handleChange} 32 onBlur={handleBlur} 33 className={error ? "input-error" : ""} 34 /> 35 {error && <p className="error-message">{error}</p>} 36 </div> 37 ); 38}
This pattern:
For complex forms, consider using validation libraries such as Formik, React Hook Form, or Yup.
1import { Formik, Form, Field, ErrorMessage } from "formik"; 2import * as Yup from "yup"; 3 4const validationSchema = Yup.object({ 5 name: Yup.string() 6 .max(15, "Must be 15 characters or less") 7 .required("Required"), 8 email: Yup.string() 9 .email("Invalid email address") 10 .required("Required"), 11 password: Yup.string() 12 .min(8, "Password must be at least 8 characters") 13 .required("Required") 14 .matches( 15 /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 16 "Must contain at least one uppercase letter, one lowercase letter, and one number" 17 ) 18}); 19 20function FormikValidatedForm() { 21 return ( 22 <Formik 23 initialValues={{ 24 name: "", 25 email: "", 26 password: "" 27 }} 28 validationSchema={validationSchema} 29 onSubmit={(values, { setSubmitting }) => { 30 setTimeout(() => { 31 alert(JSON.stringify(values, null, 2)); 32 setSubmitting(false); 33 }, 400); 34 }} 35 > 36 {({ isSubmitting }) => ( 37 <Form> 38 <div> 39 <label htmlFor="name">Name</label> 40 <Field type="text" name="name" /> 41 <ErrorMessage name="name" component="div" className="error" /> 42 </div> 43 44 <div> 45 <label htmlFor="email">Email</label> 46 <Field type="email" name="email" /> 47 <ErrorMessage name="email" component="div" className="error" /> 48 </div> 49 50 <div> 51 <label htmlFor="password">Password</label> 52 <Field type="password" name="password" /> 53 <ErrorMessage name="password" component="div" className="error" /> 54 </div> 55 56 <button type="submit" disabled={isSubmitting}> 57 Submit 58 </button> 59 </Form> 60 )} 61 </Formik> 62 ); 63}
Benefits of using validation libraries:
1const validateEmail = (email) => { 2 const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 3 return regex.test(email); 4};
1const validatePassword = (password) => { 2 // At least 8 characters, one uppercase, one lowercase, one number 3 const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/; 4 return regex.test(password); 5};
1const validateURL = (url) => { 2 try { 3 new URL(url); 4 return true; 5 } catch (e) { 6 return false; 7 } 8};
1const validateCreditCard = (cardNumber) => { 2 // Remove spaces and dashes 3 cardNumber = cardNumber.replace(/[\s-]/g, ""); 4 5 if (!/^\d+$/.test(cardNumber)) return false; 6 7 // Luhn Algorithm 8 let sum = 0; 9 let alternate = false; 10 11 for (let i = cardNumber.length - 1; i >= 0; i--) { 12 let n = parseInt(cardNumber.charAt(i), 10); 13 14 if (alternate) { 15 n *= 2; 16 if (n > 9) n -= 9; 17 } 18 19 sum += n; 20 alternate = !alternate; 21 } 22 23 return sum % 10 === 0; 24};
Validate at the right time
Provide clear error messages
Use visual indicators
Implement progressive validation
Handle special cases
Effective form validation is essential for creating robust and user-friendly React applications. By combining the right validation techniques with thoughtful error messaging and user experience design, you can guide users to provide valid data while minimizing frustration. Whether you choose basic HTML validation, custom React state-based validation, or comprehensive validation libraries, implementing validation correctly will enhance both the security and usability of your forms.