Ad – 728Γ—90
🌐 Forms

HTML Fieldset and Legend – Grouping Form Fields

Long forms become far more usable when related fields are grouped together. The <fieldset> element wraps a logical group of form controls, and the <legend> element labels the group. Together they are one of HTML's most important β€” yet often overlooked β€” tools for both visual organisation and accessibility.

⏱️ 11 min read🎯 BeginnerπŸ“… Updated 2026

The fieldset Element

The <fieldset> element groups related form controls within a visual border. It is a block-level element and can contain any form controls: inputs, selects, textareas, and other fieldsets.

HTML
<form action="/order" method="POST">

  <fieldset>
    <legend>Personal information</legend>

    <label for="full-name">Full name</label>
    <input type="text" id="full-name" name="name" required>

    <label for="email-pi">Email address</label>
    <input type="email" id="email-pi" name="email" required>

  </fieldset>

  <button type="submit">Continue</button>

</form>

By default, browsers render a visible border around the fieldset and position the legend text overlapping the top border β€” a distinctive look that immediately signals a grouped section to sighted users.

The legend Element

The <legend> element must be the first child of a <fieldset>. It provides a caption or title for the group. A fieldset without a legend is allowed but leaves screen reader users without a group label.

HTML
<fieldset>
  <legend>Payment details</legend>
  <!-- form controls here -->
</fieldset>

<!-- Legend can contain HTML for richer styling -->
<fieldset>
  <legend><strong>Billing address</strong> <span class="required-note">* required</span></legend>
  <!-- form controls here -->
</fieldset>

Accessibility Benefits

The combination of <fieldset> and <legend> provides a crucial accessibility benefit: screen readers announce the legend text before the label of each field inside the group. This gives context that would otherwise be missing.

For example, a form with two groups of radio buttons β€” "Delivery method" and "Payment method" β€” without fieldsets would be announced as just "Standard" and "Express" with no context. With fieldsets, screen readers say "Delivery method group β€” Standard" and "Payment method group β€” Credit card".

HTML
<!-- βœ… Correct: radio group inside fieldset with legend -->
<fieldset>
  <legend>Delivery method</legend>
  <label><input type="radio" name="delivery" value="standard"> Standard (3–5 days)</label>
  <label><input type="radio" name="delivery" value="express"> Express (next day)</label>
  <label><input type="radio" name="delivery" value="same-day"> Same day</label>
</fieldset>

<!-- βœ… Correct: checkbox group inside fieldset with legend -->
<fieldset>
  <legend>Notification preferences</legend>
  <label><input type="checkbox" name="notify" value="email"> Email updates</label>
  <label><input type="checkbox" name="notify" value="sms"> SMS alerts</label>
  <label><input type="checkbox" name="notify" value="push"> Push notifications</label>
</fieldset>
Always use fieldset + legend for radio and checkbox groups. Without a fieldset, screen reader users hear each radio option in isolation ("Standard", "Express") without knowing they belong to the "Delivery method" question. This is a common accessibility failure on real-world forms.
Ad – 336Γ—280

Disabled fieldset

Adding the disabled attribute to a <fieldset> disables all form controls inside it with a single attribute. This is far more convenient than adding disabled to every individual input.

HTML
<form action="/checkout" method="POST">

  <fieldset>
    <legend>Shipping address</legend>
    <label for="ship-line1">Address line 1</label>
    <input type="text" id="ship-line1" name="ship_line1">
    <label for="ship-city">City</label>
    <input type="text" id="ship-city" name="ship_city">
    <label for="ship-postcode">Postcode</label>
    <input type="text" id="ship-postcode" name="ship_postcode">
  </fieldset>

  <!-- Disabled fieldset: all inputs inside are greyed out and non-interactive -->
  <fieldset disabled id="billing-fieldset">
    <legend>
      Billing address
      <label>
        <input type="checkbox" id="same-as-shipping">
        Same as shipping
      </label>
    </legend>
    <label for="bill-line1">Address line 1</label>
    <input type="text" id="bill-line1" name="bill_line1">
    <label for="bill-city">City</label>
    <input type="text" id="bill-city" name="bill_city">
  </fieldset>

</form>
JavaScript
// Toggle billing fieldset based on checkbox
const checkbox = document.getElementById('same-as-shipping');
const billing  = document.getElementById('billing-fieldset');

checkbox.addEventListener('change', function() {
  billing.disabled = this.checked;
});
Disabled fieldset inputs are not submitted. When a fieldset is disabled, none of its inputs are included in the form submission. If you need the values to be sent to the server even when the section is disabled (e.g., copying shipping to billing server-side), use readonly on individual inputs instead.

Practical Example: Multi-Section Form

Here is a complete checkout form with three fieldsets for personal details, shipping, and payment.

HTML
<form action="/checkout/confirm" method="POST">

  <fieldset>
    <legend>Personal details</legend>

    <div class="form-row">
      <div class="form-group">
        <label for="co-fname">First name *</label>
        <input type="text" id="co-fname" name="first_name" required>
      </div>
      <div class="form-group">
        <label for="co-lname">Last name *</label>
        <input type="text" id="co-lname" name="last_name" required>
      </div>
    </div>

    <div class="form-group">
      <label for="co-email">Email address *</label>
      <input type="email" id="co-email" name="email" required autocomplete="email">
    </div>
  </fieldset>

  <fieldset>
    <legend>Shipping address</legend>

    <div class="form-group">
      <label for="co-addr1">Address line 1 *</label>
      <input type="text" id="co-addr1" name="address_1" required>
    </div>
    <div class="form-group">
      <label for="co-addr2">Address line 2</label>
      <input type="text" id="co-addr2" name="address_2">
    </div>
    <div class="form-row">
      <div class="form-group">
        <label for="co-city">City *</label>
        <input type="text" id="co-city" name="city" required>
      </div>
      <div class="form-group">
        <label for="co-post">Postcode *</label>
        <input type="text" id="co-post" name="postcode" required>
      </div>
    </div>
  </fieldset>

  <fieldset>
    <legend>Payment method</legend>

    <label><input type="radio" name="payment" value="card" checked> Credit / Debit card</label>
    <label><input type="radio" name="payment" value="paypal"> PayPal</label>
    <label><input type="radio" name="payment" value="bank"> Bank transfer</label>

  </fieldset>

  <button type="submit">Place order</button>

</form>

Styling Fieldsets with CSS

The browser's default fieldset border and legend rendering can be completely overridden with CSS. A common pattern is to remove the default border and use custom dividers or card styles.

CSS
/* Remove default border and padding */
fieldset {
  border: none;
  padding: 0;
  margin: 0 0 2rem;
}

/* Custom section divider style */
fieldset {
  border: 1px solid #dee2e6;
  border-radius: 8px;
  padding: 1.5rem;
  margin-bottom: 2rem;
}

legend {
  font-size: 1.1rem;
  font-weight: 600;
  color: #212529;
  padding: 0 0.5rem;
}

/* Card-style fieldset (no visible border, just background) */
fieldset.card-section {
  border: none;
  background: #f8f9fa;
  border-radius: 8px;
  padding: 1.5rem;
}

fieldset.card-section legend {
  background: #0d6efd;
  color: #fff;
  padding: 0.25rem 1rem;
  border-radius: 20px;
  font-size: 0.9rem;
}

/* Disabled fieldset styling */
fieldset:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

πŸ“‹ Summary

  • <fieldset> groups related form controls visually and semantically; renders a border by default.
  • <legend> must be the first child of fieldset; provides the group's accessible name.
  • Screen readers announce the legend before each control inside β€” essential context for radio and checkbox groups.
  • disabled on a fieldset disables all child inputs at once β€” a convenient shortcut, but disabled inputs are not submitted.
  • Use one fieldset per logical section (personal info, shipping address, payment) on long forms.
  • Default browser styles can be completely replaced with CSS; a common approach is to remove the border and apply card or section styles.

Frequently Asked Questions

Is fieldset only for radio and checkbox groups?

No. Fieldset is great for any group of related fields β€” for example, a shipping address section (street, city, postcode, country), a "personal details" group, or a "payment details" group. While it is most commonly recommended for radio and checkbox groups (because it is the only semantic way to name those groups for screen readers), it adds value wherever you have logically related controls that benefit from a group label.

Can I nest fieldsets?

Yes, fieldsets can be nested. Each nested fieldset should have its own legend. However, deeply nested fieldsets are rare in practice. A common use case is an outer fieldset for "Addresses" containing two inner fieldsets for "Shipping address" and "Billing address".

How do I remove the default fieldset border?

Set border: none on the fieldset in CSS. You may also need to reset padding: 0 and margin: 0 since browsers apply default padding to fieldset elements. Use min-width: 0 if the fieldset is inside a flexbox container β€” fieldsets have a min-width: min-content quirk that can cause layout issues in flex/grid.

Does a disabled fieldset submit any data at all?

No. When a fieldset is disabled, all form controls inside it are effectively disabled β€” their names and values are excluded from the form submission entirely, just as if each individual input had the disabled attribute. If you need to submit the values but keep the fields non-editable, use readonly on each input instead (note that readonly is not available on select or button elements).