Grouping Form Controls — <fieldset> and <legend>
When a form contains related controls — a group of radio buttons, a set of checkboxes, or a block of address fields — those controls should be explicitly grouped in the HTML. The <fieldset> and <legend> elements exist precisely for this purpose.
The problem with bare groups
Section titled “The problem with bare groups”In the previous lesson you added checkboxes and radio buttons to your form using a <p> element as a visual label:
<p>Preferred trail difficulty:</p><input type="radio" id="level-easy" name="difficulty" value="easy"><label for="level-easy">Easy</label>Visually, the <p> looks like a group label. But to a screen reader, that paragraph is just text — it has no connection to the inputs below it. A screen reader user navigating by form controls would hear “Easy, radio button” with no context about what they are choosing.
<fieldset> — the group container
Section titled “<fieldset> — the group container”<fieldset> wraps a group of related form controls and their labels. It draws a visible border around the group by default (which you can style away with CSS).
<fieldset> <input type="radio" id="level-easy" name="difficulty" value="easy"> <label for="level-easy">Easy</label>
<input type="radio" id="level-moderate" name="difficulty" value="moderate"> <label for="level-moderate">Moderate</label>
<input type="radio" id="level-strenuous" name="difficulty" value="strenuous"> <label for="level-strenuous">Strenuous</label></fieldset><legend> — the group label
Section titled “<legend> — the group label”<legend> is the caption for a <fieldset>. It must be the first element inside <fieldset>. Screen readers announce the <legend> text before each control in the group, giving every radio button and checkbox the context it needs.
<fieldset> <legend>Preferred trail difficulty</legend>
<input type="radio" id="level-easy" name="difficulty" value="easy"> <label for="level-easy">Easy</label>
<input type="radio" id="level-moderate" name="difficulty" value="moderate"> <label for="level-moderate">Moderate</label>
<input type="radio" id="level-strenuous" name="difficulty" value="strenuous"> <label for="level-strenuous">Strenuous</label></fieldset>A screen reader will now announce each option with its full context: “Preferred trail difficulty. Easy, radio button, 1 of 3.”
When to use <fieldset> and <legend>
Section titled “When to use <fieldset> and <legend>”Use them whenever you have a group of controls that belong together under a single label:
- Radio button groups — always (radio buttons without a
<fieldset>/<legend>are always missing context) - Checkbox groups — when the checkboxes share a common question
- Address fields —
<fieldset><legend>Shipping address</legend>...fields...</fieldset>
Do not use <fieldset> for a single labeled input — <label> is sufficient there.
A complete grouped form
Section titled “A complete grouped form”<form> <label for="contact-name">Your name</label> <input type="text" id="contact-name" name="name" required>
<label for="contact-email">Email address</label> <input type="email" id="contact-email" name="email" required>
<fieldset> <legend>What gear do you have?</legend> <input type="checkbox" id="gear-boots" name="gear" value="boots"> <label for="gear-boots">Hiking boots</label>
<input type="checkbox" id="gear-pack" name="gear" value="pack"> <label for="gear-pack">Backpack</label>
<input type="checkbox" id="gear-map" name="gear" value="map"> <label for="gear-map">Trail map</label> </fieldset>
<fieldset> <legend>Preferred trail difficulty</legend> <input type="radio" id="level-easy" name="difficulty" value="easy"> <label for="level-easy">Easy</label>
<input type="radio" id="level-moderate" name="difficulty" value="moderate"> <label for="level-moderate">Moderate</label>
<input type="radio" id="level-strenuous" name="difficulty" value="strenuous"> <label for="level-strenuous">Strenuous</label> </fieldset>
<button type="submit">Send</button></form>The default <fieldset> border
Section titled “The default <fieldset> border”Browsers apply a visible border and indent the <legend> text into the top border by default. This styling is entirely CSS-controllable — in CSS Foundations you will learn to reset it or restyle it to match your design. For now, the default appearance is fine.
Exercise
Section titled “Exercise”Open index.html in VS Code.
Find the checkboxes and radio buttons you added in the previous lesson. They are currently grouped with <p> elements as visual labels.
Replace each <p> group label with a proper <fieldset> and <legend>:
Before:
<p>What are you interested in?</p><input type="checkbox" id="interest-tips" name="interest" value="tips"><label for="interest-tips">Tips and advice</label>After:
<fieldset> <legend>What are you interested in?</legend> <input type="checkbox" id="interest-tips" name="interest" value="tips"> <label for="interest-tips">Tips and advice</label></fieldset>Do the same for your radio button group.
Save and open index.html in your browser. You should see a bordered box around each group with the legend text appearing at the top of the border.
<fieldset>groups related form controls together. Use it for radio button groups, checkbox groups, and any set of inputs that share a common question.<legend>is the visible and accessible label for the group. It must be the first child of<fieldset>.- Screen readers announce the
<legend>text before each control in the group — without it, users lose the context for what they are choosing. <p>elements as group labels are visual-only. They have no semantic connection to the inputs below them.- The default
<fieldset>border is controlled entirely by CSS and can be removed or restyled.
Lesson 06 introduces the final set of form tools — attributes that improve usability and add built-in browser validation.