HTML Form Accessibility

Making forms usable for everyone

â™ŋ Why Form Accessibility Matters

Accessible forms ensure all users, including those with disabilities, can interact with your website effectively using screen readers and other assistive technologies.


<!-- Accessible form example -->
<label for="email">Email Address</label>
<input type="email" id="email" required 
       aria-describedby="email-help">
<div id="email-help">We'll never share your email</div>
                                    

Output:

We'll never share your email

Proper Labels

đŸˇī¸

Explicit Labels

Use for attribute to connect labels

<label for="name">Name</label>
<input id="name" type="text">
🔗

Implicit Labels

Wrap input inside label

<label>
  Name: <input type="text">
</label>
📝

aria-label

For inputs without visible labels

<input type="search" 
       aria-label="Search products">
📖

aria-labelledby

Reference existing text as label

<h2 id="billing">Billing</h2>
<input aria-labelledby="billing">

📋 Fieldsets and Legends

Group related form controls for better organization:

<fieldset>
  <legend>Contact Information</legend>
  
  <label for="fname">First Name</label>
  <input type="text" id="fname" required>
  
  <label for="lname">Last Name</label>
  <input type="text" id="lname" required>
  
  <label for="phone">Phone</label>
  <input type="tel" id="phone">
</fieldset>

Output:

Contact Information

â„šī¸ Descriptions and Help Text

Provide additional context with aria-describedby:

<label for="password">Password</label>
<input type="password" id="password" 
       aria-describedby="pwd-help" required>
<div id="pwd-help">
  Must be at least 8 characters with numbers and letters
</div>

<label for="username">Username</label>
<input type="text" id="username" 
       aria-describedby="user-help">
<div id="user-help">
  Choose a unique username (3-20 characters)
</div>

Output:

Must be at least 8 characters with numbers and letters
Choose a unique username (3-20 characters)

âš ī¸ Error Messages

Make error messages accessible and clear:

<label for="email-err">Email</label>
<input type="email" id="email-err" 
       aria-describedby="email-error" 
       aria-invalid="true" required>
<div id="email-error" role="alert">
  Please enter a valid email address
</div>

<!-- Success state -->
<label for="email-ok">Email</label>
<input type="email" id="email-ok" 
       aria-describedby="email-success" 
       aria-invalid="false">
<div id="email-success">
  ✓ Valid email address
</div>

Output:

✓ Valid email address

âŒ¨ī¸ Keyboard Navigation

Ensure forms work with keyboard-only navigation:

<!-- Proper tab order -->
<input type="text" tabindex="1">
<input type="email" tabindex="2">
<button type="submit" tabindex="3">Submit</button>

<!-- Skip to main content -->
<a href="#main-form" class="skip-link">Skip to form</a>

<form id="main-form">
  <!-- Form content -->
</form>

Output:



🧠 Test Your Knowledge

Which attribute connects a label to its input field?