I often see front-end developers wrap a legend element in a div in order to have more styling options. Unfortunately, that makes the legend element useless.
Rule: the legend element must always be the first child element in a fieldset element.
Why?
When this condition is fulfilled, screen readers will read the legend when the first form field in the fieldset receives keyboard focus. If any other element is wrapped around the legend element (usually a div, but p and other element must also be excluded), this will not work.
The HTML specification requires that the legend element must always be the first child element in a fieldset element. The W3C Validator reports a validation error when the legend element is not the first child element in a fieldset element, but most developers don’t seem to use the W3C Validator.
Snippet of non-compliant code:
<fieldset>
<div class="...">
<legend>Gender</legend>
</div>
<!-- Form elements go here. -->
</fieldset>
Snippet of compliant code:
<fieldset>
<legend>Gender</legend>
<!-- Form elements go here; div elements are fine here. -->
</fieldset>
Potential exception
Potentially, an exception could be made if the fieldset has an aria-labelledby attribute that references the ID of the legend element, but I have never seen this in the wild:
<fieldset aria-labelledby="legend-ID">
<div class="...">
<legend id="legend-ID">Gender</legend>
</div>
<!-- Form elements go here. -->
</fieldset>
I used the W3C Validator a lot when success criterion 4.1.1 Parsing was still part of WAG, but WCAG 2.2 got rid of it and it is now “considered as always satisfied for any content using HTML or XML” even in WCAG 2.1.
I still find it useful as a sanity check on my code, but it has most value if you check the DOM instead of giving it a URL. This is because modern websites rely a lot on JavaScript for adding or enabling all sorts of components (menus, form validation, forms with conditional sections, et etc) after page load.
Unfortunately, checking the DOM is currently not very convenient. The steps are as follows:
Make sure the page is in the state in which you want to check it. (This is not necessarily the state just after page load; it may also be a state after a few interactions.) Also make sure you have temporarily disabled any browser addons that insert code into the DOM while enabled.
Open the DevTools or Inspector to visualise the DOM.
Put the cursor on the html element, press F2, then Ctrl A (to select the entire DOM) and finally Ctrl C (to copy the DOM).
Go to the validator and switch to the tab “Validate by Direct Input”.
Type the doctype into fhe field (<!DOCTYPE html>), then press Ctrl V to paste the DOM below it.
Press Check and inspect the results.
This is way too many steps. Ideally, you would have a “Validate the DOM” button that takes care of steps 2–5.