Master React form validation with Axios for user registration
Table of Contents
- Introduction
- Creating a React Registration Form
- Adding Custom Validation
- Considerations for Accessibility
- Installing Required Dependencies
- Importing Font Awesome Icons
- Validating the Username Field
- Validating the Password Field
- Validating the Confirmation Field
- Adding a Submit Button
- Handling Form Submission
- Displaying Success and Error Messages
- Integration with a Backend
- Testing the Registration Form
- Conclusion
Introduction
In this tutorial, we will learn how to Create a React registration form with custom validation and accessibility features. We will be using React hooks, such as useRef
, useState
, and useEffect
, to manage the form state and perform validation. Additionally, we will be integrating Font Awesome icons for visual feedback and enhancing accessibility by providing clear instructions and error messages for screen readers.
Creating a React Registration Form
Before we begin, it is important to note that this tutorial assumes a basic understanding of React and React hooks. If You are new to React, I recommend taking a beginner-level course or tutorial to familiarize yourself with the fundamentals.
To get started, open your code editor and create a new React project. Clear out any unnecessary files and dependencies that were automatically generated. In this tutorial, we will only need the react
, react-dom
, and react-scripts
packages. You can install any additional dependencies, such as Font Awesome, later on if needed.
Adding Custom Validation
For our registration form, we will be validating the username, password, and confirmation fields. The username must start with a letter and can contain letters, numbers, hyphens, or underscores. It should be between 4 and 24 characters long. The password must include at least one lowercase letter, one uppercase letter, one digit, and one special character. It should be between 8 and 24 characters long. The confirmation field should match the password field exactly.
We will be using regular expressions (regex) to perform the validation. Here are the regex Patterns for the username and password:
// Username regex pattern
const userRegex = /^[a-zA-Z][a-zA-Z0-9-_]{3,23}$/;
// Password regex pattern
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,24}$/;
To handle validation, we will use React hooks such as useState
, useEffect
, and useRef
. The useState
hook will be used to manage the state of the input fields, the useEffect
hook will handle validation whenever the state changes, and the useRef
hook will allow us to set the focus on specific elements.
Considerations for Accessibility
Throughout the creation of the registration form, we will be considering accessibility. We aim to provide clear instructions and error messages, as well as ensure proper keyboard navigation and screen reader compatibility. We will use semantic HTML elements, such as <section>
and <label>
, and add appropriate attributes, such as aria-invalid
and aria-describedby
, to enhance accessibility.
To further improve accessibility, we will integrate Font Awesome icons for visual feedback. The icons will change dynamically Based on the validity of the input fields. We will also announce error messages using screen readers by setting the aria-live
attribute to "assertive".
Installing Required Dependencies
To use Font Awesome icons in our React project, we need to install the @fortawesome/fontawesome-svg-Core
, @fortawesome/free-solid-svg-icons
, and @fortawesome/react-fontawesome
packages. You can install these dependencies using the following command:
npm install @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesome
After installing the dependencies, we can begin importing and using Font Awesome icons in our code.
Importing Font Awesome Icons
To use Font Awesome icons, we need to import them and the required components. In our case, we will be using the faCheck
, faTimes
, and faInfoCircle
icons. First, import the necessary hooks and components:
import { useRef, useState, useEffect } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCheck, faTimes, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
We can now utilize these icons in our form by adding them dynamically based on the validity of the input fields.
Validating the Username Field
To validate the username field, we will use the useState
and useEffect
hooks. Whenever the username field changes, we will perform the validation and update the validName
state accordingly. We will also add visual feedback by displaying a green checkmark or a red cross using Font Awesome icons.
Here is the code snippet for validating the username field:
// State for username field and validation
const [user, setUser] = useState('');
const [validName, setValidName] = useState(false);
// Regex for username validation
const userRegex = /^[a-zA-Z][a-zA-Z0-9-_]{3,23}$/;
// Ref for setting focus on the username input
const userRef = useRef();
// Set focus on username input when component loads
useEffect(() => {
userRef.current.focus();
}, []);
// Validate username field whenever it changes
useEffect(() => {
const isValid = userRegex.test(user);
setValidName(isValid);
}, [user]);
Notice that we use the userRef
to set the focus on the username input when the component loads. This ensures that users can navigate and Interact with the form using keyboard navigation.
Validating the Password Field
Similar to the username field, we will use the useState
, useEffect
, and useRef
hooks to validate the password field. We will also provide visual feedback using Font Awesome icons.
Here is the code snippet for validating the password field:
// State for password field and validation
const [password, setPassword] = useState('');
const [validPassword, setValidPassword] = useState(false);
// Regex for password validation
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,24}$/;
// Ref for setting focus on the password input
const passwordRef = useRef();
// Validate password field whenever it changes
useEffect(() => {
const isValid = passwordRegex.test(password);
setValidPassword(isValid);
}, [password]);
Just like in the username field, we use the passwordRef
to set the focus on the password input when the component loads.
Validating the Confirmation Field
To validate the confirmation field, we need to compare it with the password field. We will utilize the useState
, useEffect
, and useRef
hooks to manage this validation. Similarly, we will display visual feedback using Font Awesome icons.
Here is the code snippet for validating the confirmation field:
// State for confirmation field and match validation
const [matchPassword, setMatchPassword] = useState('');
const [validMatch, setValidMatch] = useState(false);
// Ref for setting focus on the confirmation input
const matchRef = useRef();
// Validate confirmation field whenever it changes
useEffect(() => {
const isValid = password === matchPassword;
setValidMatch(isValid);
}, [password, matchPassword]);
Again, we set the focus on the confirmation input using the matchRef
when the component loads.
Adding a Submit Button
Now that our form is validated, we need to add a submit button to allow users to complete the registration process. In React, when there's only one button in a form, it is automatically considered the submit button. Therefore, we do not need to explicitly specify the Type
attribute as "submit". We can simply add the button and disable it until all fields are valid.
Here is the code snippet for the submit button:
// Disable submit button if any field is invalid
const isButtonDisabled = !validName || !validPassword || !validMatch;
// JSX for the submit button
<button disabled={isButtonDisabled}>Sign Up</button>
By disabling the button until all fields are valid, we ensure that users cannot submit incomplete or incorrect information.
Handling Form Submission
To handle the form submission, we need to add an onSubmit
event to the form element. In our case, we will call a function named handleSubmit
, which will handle the submission process. We will use the axios
library to make an API request to our backend server and handle any errors or success messages that we receive.
Here is the code snippet for handling form submission:
// Function to handle form submission
const handleSubmit = async (event) => {
event.preventDefault();
try {
const response = await axios.post(registerUrl, JSON.stringify({ user, pwd }), {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
});
// Handle success and display success message
console.log(response.data);
setSuccess(true);
} catch (error) {
if (!error.response) {
setErrorMessage('No server response');
} else if (error.response.status === 409) {
setErrorMessage('Username taken');
} else {
setErrorMessage('Registration failed');
}
}
};
In the handleSubmit
function, we prevent the default form submission behavior using event.preventDefault()
. We then make a POST
request to our backend server using axios.post
. We send the user
and pwd
(password) as the request payload. The headers
object ensures that the request is sent with the correct content-type. We also set withCredentials
to true
to include any existing cookies in the request.
If the request is successful, we log the response data to the console and set the success
state to true
. If an error occurs, we handle different response statuses and set the appropriate error message.
Displaying Success and Error Messages
To provide feedback to the user, we will display success and error messages based on the form submission result. We will update the JSX to render a success message when the success
state is true
, and an error message when the errorMessage
state exists.
Here is the code snippet for displaying the success and error messages:
{success ? (
<section>
<h2>Success</h2>
<p>Registration successful! Please sign in.</p>
<Link to="/signin">Sign In</Link>
</section>
) : (
<form onSubmit={handleSubmit}>
{/* Rest of the form JSX */}
</form>
)}
{errorMessage && (
<p>{errorMessage}</p>
)}
We use a ternary operator to conditionally render either the success section or the registration form. Additionally, if the errorMessage
state exists, we render a Paragraph element displaying the error message.
Integration with a Backend
To complete the registration process, we need to integrate our frontend registration form with a backend server. In this tutorial, we assume that you have a backend server set up to handle the registration endpoint. If not, you can create a simple RESTful API using tools like Node.js and Express.
First, we need to define the base URL for our API. This should be set to the URL of your backend server where the registration endpoint exists. You can define this URL in a separate file, such as axios.js
, and export it for use in other components.
Here is an example of the axios.js
file:
import axios from 'axios';
export default axios.create({
baseURL: 'http://localhost:3500',
});
In this example, the base URL is set to http://localhost:3500
. Replace this with the URL of your backend server.
To use this axios
instance in your register component, import it at the top of the file:
import axios from '../api/axios';
Make sure to update the import path relative to your project's file structure.
Finally, update the handleSubmit
function to use the axios
instance and send the registration data to the backend:
const handleSubmit = async (event) => {
event.preventDefault();
try {
const response = await axios.post('/register', { user, pwd });
// Handle success and display success message
console.log(response.data);
setSuccess(true);
} catch (error) {
if (!error.response) {
setErrorMessage('No server response');
} else if (error.response.status === 409) {
setErrorMessage('Username taken');
} else {
setErrorMessage('Registration failed');
}
}
};
In this example, We Are assuming that the registration endpoint is /register
. Modify this endpoint according to your backend server implementation.
Testing the Registration Form
Now that our registration form in complete, we can test it by running both the frontend React application and the backend server simultaneously.
First, start the backend server by navigating to the server directory in a separate terminal window and running the command npm run dev
.
Next, in another terminal window, navigate to the frontend React application directory and run the command npm start
to start the React development server.
Open your web browser and navigate to the URL displayed in the terminal where the React application is running. You should now be able to access the registration form and test its functionality.
Try submitting the form with both valid and invalid data to ensure that the validation and error handling are working correctly. You can also check the browser's console for any responses from the backend server.
Conclusion
In this tutorial, we have learned how to create a React registration form with custom validation and accessibility features. We have explored various React hooks such as useState
, useEffect
, and useRef
to manage the state and perform validation. Additionally, we have used the axios
library to handle form submissions and interact with a backend server.
By focusing on accessibility throughout the form creation process, we have ensured that our form is more inclusive and user-friendly. The use of semantic HTML elements, appropriate attributes, and clear instructions and error messages help improve the overall user experience.
Remember to test your form thoroughly and make any necessary adjustments based on your specific requirements and backend implementation.
Thank you for following along with this tutorial. Happy coding!