Use <label>, <fieldset>, and <legend> to make forms easier to understand and navigate—especially for screen reader and keyboard users. Labels connect text to inputs; fieldsets group related controls; legends title those groups so the purpose of each section is clear.
for/id, or by wrapping the control inside the label.Basic pattern for using these elements together:
<fieldset>
<legend>Group title</legend>
<label for="field-id">Field label</label>
<input id="field-id" name="field-name">
</fieldset>
You can also wrap a control directly in a label (no for/id needed), which is common for radio buttons and checkboxes.
<!-- Group inputs using fieldset and legend -->
<fieldset>
<legend>Personal Information</legend>
<label for="name" class="req">Full Name</label>
<input type="text" id="name" name="fullname" placeholder="Enter your full name" required
aria-describedby="name-help">
<small id="name-help" class="help">As shown on official documents.</small>
<label for="email" class="req">Email Address</label>
<input type="email" id="email" name="email" placeholder="name@example.com" required
aria-describedby="email-help">
<small id="email-help" class="help">We’ll send a confirmation email.</small>
</fieldset>
<!-- Radios/checkboxes belong in a fieldset with a legend -->
<fieldset>
<legend>Contact Preference</legend>
<label><input type="radio" name="contact" value="email" checked> Email</label>
<label><input type="radio" name="contact" value="phone"> Phone</label>
</fieldset>
This demo shows two fieldsets: one for personal information and one for contact preference. Each label is associated with its input, and help/error text is linked using aria-describedby.
<legend> short and descriptive (a few words). Put it first inside the fieldset.aria-describedby so assistive tech reads guidance with the control.for/id or wrap the control inside the label—both patterns create a clickable label.<fieldset disabled> disables all form controls inside it (useful for read-only sections).for/id values match and that id values are unique on the page.aria-describedby.aria-describedby..error elements next to each field (similar to the live demo).<fieldset disabled> example for a “Billing (read-only)” section to see how all inner controls are disabled together.