What this example teaches
- How visible labels connect to inputs.
- Why placeholder-only fields are risky.
- How required text, errors, and grouped radio buttons need structure.
Proper label for input
Bad
<input id="email" name="email" type="email"> The field has no visible or programmatic label.
Better
<label for="email">Email address</label>
<input id="email" name="email" type="email"> The label is visible and connected to the input with for and id.
Placeholder-only field
Bad
<input name="name" placeholder="Full name"> The placeholder disappears when users type and may not work as a reliable label.
Better
<label for="name">Full name</label>
<input id="name" name="name" placeholder="Jane Smith"> The label remains visible, and the placeholder is only an example.
Required field text
Bad
<label for="phone">Phone</label>
<input id="phone" required> Required may be announced by some technology, but the visible page does not explain it clearly.
Better
<label for="phone">Phone <span aria-hidden="true">*</span></label>
<p id="phone-hint">Required. Use 10 digits.</p>
<input id="phone" required aria-describedby="phone-hint"> The field has visible instructions and a programmatic description.
Error message association
Bad
<label for="postal">Postal code</label>
<input id="postal">
<p class="error">Enter a valid postal code.</p> The error may be visible but not connected to the field.
Better
<label for="postal">Postal code</label>
<input id="postal" aria-invalid="true" aria-describedby="postal-error">
<p id="postal-error" class="error">Enter a valid Canadian postal code, such as K1A 0B1.</p> The field exposes its error state and points to the error message.
Grouped radio buttons
Bad
<p>Contact preference</p>
<label><input type="radio" name="contact"> Email</label>
<label><input type="radio" name="contact"> Phone</label> The group label is not programmatically tied to the radio choices.
Better
<fieldset>
<legend>Contact preference</legend>
<label><input type="radio" name="contact" value="email"> Email</label>
<label><input type="radio" name="contact" value="phone"> Phone</label>
</fieldset> The legend gives the group a clear accessible name.
Contact form example
Bad
<input placeholder="Name">
<input placeholder="Email">
<textarea placeholder="Message"></textarea>
<button>Submit</button> The fields depend on placeholders and the submit button is generic.
Better
<label for="contact-name">Name</label>
<input id="contact-name" name="name">
<label for="contact-email">Email address</label>
<input id="contact-email" name="email" type="email">
<label for="message">Message</label>
<textarea id="message" name="message"></textarea>
<button type="submit">Send message</button> Each control has a persistent label and the button describes the action.
Checkbox group
Bad
<p>Interests</p>
<label><input type="checkbox" name="interest" value="news"> News</label>
<label><input type="checkbox" name="interest" value="events"> Events</label> The group heading is not programmatically tied to the checkboxes; a screen reader may not announce the relationship.
Better
<fieldset>
<legend>Interests</legend>
<label><input type="checkbox" name="interest" value="news"> News</label>
<label><input type="checkbox" name="interest" value="events"> Events</label>
</fieldset> Wrapping checkboxes in a fieldset with a legend gives the group a clear accessible name.
Submit button text
Bad
<button type="submit">Submit</button>
<button type="submit"><svg aria-hidden="true" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"></path></svg></button> "Submit" is generic and does not describe the action. The icon button has no accessible name at all.
Better
<button type="submit">Send message</button>
<button type="submit" aria-label="Send message"><svg aria-hidden="true" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"></path></svg></button> The visible button says what it does. The icon-only button has a clear aria-label.
Autocomplete on contact fields
Bad
<label for="name">Full name</label>
<input id="name" name="name">
<label for="email">Email</label>
<input id="email" name="email" type="email"> No autocomplete hints, so assistive technology and browser autofill cannot help users fill the form.
Better
<label for="name">Full name</label>
<input id="name" name="name" autocomplete="name">
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email"> Autocomplete values help browsers and assistive tech suggest or fill common field values.
What still needs human review
- Whether labels, instructions, and errors are understandable to real users.
- Whether validation works with keyboard and assistive technology.
- Whether custom controls expose the expected name, role, state, and focus order.
- Whether CAPTCHA or spam protection is accessible.
- Whether error messages are helpful and clear for all users.
Related tools
Related issue library pages
- Form field is missing a label
- Form field appears to rely on placeholder text
- Duplicate ID found
- Radio or checkbox group appears to be missing a fieldset legend
- Validation error may not be associated with the field
- Required field may not have a visible indication