Building Accessible Forms in React Applications
Accessible forms ensure all users, including those relying on screen readers or keyboard navigation, can complete critical tasks like checkout, account creation, or support requests. In financial and eācommerce platforms, inaccessible forms directly impact conversion and compliance. Start with semantic HTML: use native <form>, <label>, and <input> elements instead of divs. Associate labels with inputs via htmlFor and id attributes, not placeholders alone. Provide clear error messages linked to fields via aria-describedby, and announce validation errors with role="alert". Ensure all interactive elements are keyboard navigable and visible focus styles are preserved. Test with screen readers (like NVDA or VoiceOver) and keyboard-only navigation. Prioritizing accessibility isnāt just ethicalāit reduces support costs, widens your audience, and often improves SEO. Treat it as a core quality attribute, not an afterthought, and integrate checks into your CI pipeline using tools like axe-core.
š»Source Code
// AccessibleLoginForm.jsx
import React, { useState } from "react";
export default function AccessibleLoginForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
const newErrors = {};
if (!email) newErrors.email = "Email is required";
if (!password) newErrors.password = "Password is required";
if (Object.keys(newErrors).length === 0) {
setIsSubmitting(true);
// Simulate API call
setTimeout(() => {
alert("Logged in successfully!");
setIsSubmitting(false);
}, 1000);
} else {
setErrors(newErrors);
}
};
return (
<form onSubmit={handleSubmit} noValidate>
<h2>Sign in to your account</h2>
<div>
<label htmlFor="email">Email address</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
aria-describedby="email-error"
required
/>
{errors.email && (
<span id="email-error" role="alert" className="error">
{errors.email}
</span>
)}
</div>
<div>
<label htmlFor="password">Password</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
aria-describedby="password-error"
required
/>
{errors.password && (
<span id="password-error" role="alert" className="error">
{errors.password}
</span>
)}
</div>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Signing in..." : "Sign in"}
</button>
</form>
);
}šRelated Snippets
Similar code snippets you might find interesting
Using Intersection Observer for Lazy Loading and Scroll-Based Animations
Leveraging Astro Islands for Interactive Content-Heavy Sites
Maintaining a Simple Global State Store in React Without Extra Libraries
š¬Comments (0)
šPlease login to post comments
No comments yet. Be the first to share your thoughts!
ā”Actions
Share this snippet:
š¤About the Author
admin
Active contributor
