We need to add validation to our ContactUs form to ensure that users provide valid data before submitting. Specifically, we need to:
First, we need to add state variables to track validation errors and whether the form has been submitted:
// Add these imports and state variables to ContactUs.jsx
import { useState, useEffect } from 'react';
function ContactUs() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [phoneType, setPhoneType] = useState('');
const [comments, setComments] = useState('');
// New state variables for validation
const [validationErrors, setValidationErrors] = useState({});
const [hasSubmitted, setHasSubmitted] = useState(false);
// Rest of the component...
}
Next, we'll create a useEffect hook that runs whenever the name or email fields change:
// Add this useEffect hook after the state variables
useEffect(() => {
const errors = {};
// Validate name field
if (!name.length) errors.name = 'Please enter your Name';
// Validate email field
if (!email.includes('@')) errors.email = 'Please provide a valid Email';
// Update validation errors state
setValidationErrors(errors);
}, [name, email]);
Now, let's modify the onSubmit function to handle validation errors:
const onSubmit = e => {
// Prevent the default form behavior so the page doesn't reload.
e.preventDefault();
// Set hasSubmitted to true to show validation errors
setHasSubmitted(true);
// Check if there are any validation errors
if (Object.values(validationErrors).length) {
return alert(`The following errors were found:
${validationErrors.name ? "* " + validationErrors.name : ""}
${validationErrors.email ? "* " + validationErrors.email : ""}`);
}
// Create a new object for the contact information.
const contactUsInformation = {
name,
email,
phone,
phoneType,
comments,
submittedOn: new Date()
};
// Log the contact information to the console.
console.log(contactUsInformation);
// Reset the form state.
setName('');
setEmail('');
setPhone('');
setPhoneType('');
setComments('');
setValidationErrors({});
setHasSubmitted(false);
};
Finally, let's update the form JSX to display error messages:
// Update the name input field section
<div>
<label htmlFor='name'>Name:</label>
<input
id='name'
type='text'
onChange={e => setName(e.target.value)}
value={name}
/>
<div className='error'>
{hasSubmitted && validationErrors.name && `* ${validationErrors.name}`}
</div>
</div>
// Update the email input field section
<div>
<label htmlFor='email'>Email:</label>
<input
id='email'
type='text'
onChange={e => setEmail(e.target.value)}
value={email}
/>
<div className='error'>
{hasSubmitted && validationErrors.email && `* ${validationErrors.email}`}
</div>
</div>
Here's the complete ContactUs component with all validations implemented:
import { useState, useEffect } from 'react';
function ContactUs() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [phoneType, setPhoneType] = useState('');
const [comments, setComments] = useState('');
const [validationErrors, setValidationErrors] = useState({});
const [hasSubmitted, setHasSubmitted] = useState(false);
useEffect(() => {
const errors = {};
if (!name.length) errors.name = 'Please enter your Name';
if (!email.includes('@')) errors.email = 'Please provide a valid Email';
setValidationErrors(errors);
}, [name, email]);
const onSubmit = e => {
// Prevent the default form behavior so the page doesn't reload.
e.preventDefault();
setHasSubmitted(true);
if (Object.values(validationErrors).length) {
return alert(`The following errors were found:
${validationErrors.name ? "* " + validationErrors.name : ""}
${validationErrors.email ? "* " + validationErrors.email : ""}`);
}
// Create a new object for the contact information.
const contactUsInformation = {
name,
email,
phone,
phoneType,
comments,
submittedOn: new Date()
};
// Ideally, you'd persist this information to a database using a RESTful API.
// For now, though, just log the contact information to the console.
console.log(contactUsInformation);
// Reset the form state.
setName('');
setEmail('');
setPhone('');
setPhoneType('');
setComments('');
setValidationErrors({});
setHasSubmitted(false);
}
return (
<div>
<h2>Contact Us</h2>
<form onSubmit={onSubmit}>
<div>
<label htmlFor='name'>Name:</label>
<input
id='name'
type='text'
onChange={e => setName(e.target.value)}
value={name}
/>
<div className='error'>
{hasSubmitted && validationErrors.name && `* ${validationErrors.name}`}
</div>
</div>
<div>
<label htmlFor='email'>Email:</label>
<input
id='email'
type='text'
onChange={e => setEmail(e.target.value)}
value={email}
/>
<div className='error'>
{hasSubmitted && validationErrors.email && `* ${validationErrors.email}`}
</div>
</div>
<div>
<label htmlFor='phone'>Phone:</label>
<input
id='phone'
type='text'
onChange={e => setPhone(e.target.value)}
value={phone}
/>
<select
name='phoneType'
onChange={e => setPhoneType(e.target.value)}
value={phoneType}
>
<option value='' disabled>
Select a phone type...
</option>
<option>Home</option>
<option>Work</option>
<option>Mobile</option>
</select>
</div>
<div>
<label htmlFor='comments'>Comments:</label>
<textarea
id='comments'
name='comments'
onChange={e => setComments(e.target.value)}
value={comments}
/>
</div>
<button>Submit</button>
</form>
</div>
);
}
export default ContactUs;
Let's break down the key concepts from our implementation:
We used two state variables for validation:
We used a useEffect hook to:
We only show error messages after the form has been submitted once:
{hasSubmitted && validationErrors.name && `* ${validationErrors.name}`}
This pattern uses the logical AND (&&) operator to conditionally render error messages only when:
We prevent form submission when validation errors exist by:
It's important to understand the limitations of client-side validation:
Best practice is to implement both:
Form validation is essential in nearly all web applications:
In real-world applications, you might use more advanced validation techniques:
Here are some examples of more sophisticated validation techniques:
// More robust email validation
if (!/\S+@\S+\.\S+/.test(email)) {
errors.email = 'Please provide a valid email address';
}
// Validate phone number format
if (phone && !/^\d{10}$/.test(phone.replace(/\D/g, ''))) {
errors.phone = 'Please enter a 10-digit phone number';
}
// Phone type is required if phone is provided
if (phone && !phoneType) {
errors.phoneType = 'Please select a phone type';
}
// Limit comment length
if (comments.length > 500) {
errors.comments = 'Comments must be less than 500 characters';
}
To continue improving your form validation skills, consider exploring: