HTML5 Fundamentals

Forms: Structure, Labels & Fieldsets

30 min Lesson 10 of 18

What Are HTML Forms?

Forms are how users send data to a server. Every login page, search bar, and contact form relies on the <form> element. A form collects input through text fields, dropdowns, and buttons, then submits that data for processing. In this lesson, you will learn to build accessible forms with proper labels, fieldsets, and semantic markup.

The form Element: action and method

The <form> element wraps all input controls. The action attribute specifies where data is sent, and method determines how. There are two methods:

  • GET -- Appends data to the URL as query parameters (e.g., ?search=html). Use GET for searches and filters where the URL should be shareable. Data is visible in the address bar.
  • POST -- Sends data in the HTTP request body, hidden from the URL. Use POST for logins, registrations, and forms that modify server data. No size limit, and data stays out of browser history.

Example: Basic Form with GET and POST

<!-- Search form using GET -->
<form action="/search" method="GET">
  <label for="query">Search:</label>
  <input type="text" id="query" name="query">
  <button type="submit">Search</button>
</form>

<!-- Contact form using POST -->
<form action="/contact" method="POST">
  <label for="email">Email:</label>
  <input type="text" id="email" name="email">
  <button type="submit">Send</button>
</form>

Labels: The Most Important Accessibility Feature

The <label> element associates a text description with a form control. This is essential for accessibility -- screen readers announce the label when a user focuses on the input, and clicking the label activates the associated control. There are two association methods:

Explicit labels use the for attribute, matching the id of the input. This is preferred because it works even when the label and input are not adjacent.

Implicit labels wrap the input inside the label element, requiring no for or id attributes.

Example: Explicit vs Implicit Labels

<!-- Explicit label (preferred) -->
<label for="username">Username:</label>
<input type="text" id="username" name="username">

<!-- Implicit label -->
<label>
  Password:
  <input type="text" id="password" name="password">
</label>
Note: The name attribute is what gets sent to the server. Without a name, the input data will not be included in the form submission. The id is used for label association and CSS targeting. Both serve different purposes and both are important.

Grouping Controls with fieldset and legend

When a form has multiple related groups of inputs, use <fieldset> to group them and <legend> to give each group a title. This is especially important for radio buttons and checkboxes, where multiple inputs share a common question. Screen readers announce the legend before each input in the group, so users understand the context.

Example: Fieldset with Legend for Radio Buttons

<form action="/survey" method="POST">
  <fieldset>
    <legend>Personal Information</legend>
    <label for="fullname">Full Name:</label>
    <input type="text" id="fullname" name="fullname">

    <label for="user-email">Email:</label>
    <input type="text" id="user-email" name="email">
  </fieldset>

  <fieldset>
    <legend>Preferred Contact Method</legend>
    <label>
      <input type="radio" name="contact" value="email"> Email
    </label>
    <label>
      <input type="radio" name="contact" value="phone"> Phone
    </label>
    <label>
      <input type="radio" name="contact" value="mail"> Mail
    </label>
  </fieldset>

  <button type="submit">Submit Survey</button>
</form>

Textarea: Multi-Line Text Input

The <textarea> element creates a resizable multi-line text field for comments, messages, or descriptions. Unlike <input>, it is not self-closing -- text between the tags becomes the default value. Use rows and cols for initial sizing, though CSS is preferred for layout control.

Select, Option, and Optgroup: Dropdown Menus

The <select> element creates a dropdown list. Each choice is an <option>. For long lists, group related options with <optgroup>. The value attribute is sent to the server, while the text content is what users see.

Example: Textarea, Select, and Optgroup

<form action="/feedback" method="POST">
  <label for="department">Department:</label>
  <select id="department" name="department">
    <option value="">-- Select a department --</option>
    <optgroup label="Engineering">
      <option value="frontend">Frontend</option>
      <option value="backend">Backend</option>
    </optgroup>
    <optgroup label="Design">
      <option value="ui">UI Design</option>
      <option value="ux">UX Research</option>
    </optgroup>
  </select>

  <label for="comments">Comments:</label>
  <textarea id="comments" name="comments" rows="5" cols="40"></textarea>

  <button type="submit">Send Feedback</button>
</form>

Button Types

The <button> element has three types that control its behavior:

  • type="submit" -- Submits the form data to the server. This is the default type if no type is specified.
  • type="reset" -- Clears all form fields back to their default values. Use this sparingly, as users rarely want to erase everything they have typed.
  • type="button" -- Does nothing by default. Use this for JavaScript-driven actions that should not submit or reset the form.
Pro Tip: Always explicitly set the type attribute on your buttons. A <button> without a type inside a form defaults to type="submit", which can cause accidental form submissions when users click buttons you intended for other purposes.

Form Layout Patterns

HTML forms have no built-in layout -- labels and inputs appear inline by default. Use a wrapping <div> around each label-input pair and style with CSS. A stacked layout works best on mobile.

Example: Stacked Form Layout with CSS

<style>
  .form-group {
    margin-bottom: 16px;
  }
  .form-group label {
    display: block;
    margin-bottom: 4px;
    font-weight: bold;
  }
  .form-group input,
  .form-group textarea {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
  }
</style>

<form action="/register" method="POST">
  <div class="form-group">
    <label for="name">Full Name:</label>
    <input type="text" id="name" name="name">
  </div>
  <div class="form-group">
    <label for="bio">Bio:</label>
    <textarea id="bio" name="bio" rows="3"></textarea>
  </div>
  <button type="submit">Register</button>
</form>
Common Mistake: Using placeholder text as a substitute for labels. Placeholders disappear when the user starts typing, leaving them with no indication of what the field expects. Always use a visible <label> element. Placeholders are supplementary hints, not replacements for labels.

Practice Exercise

Build a job application form with the following structure: Create a <fieldset> labeled "Personal Details" containing explicitly labeled text inputs for full name, email, and phone number. Create a second <fieldset> labeled "Job Preferences" containing a <select> dropdown with two <optgroup> groups (Engineering and Marketing, each with two or three role options), a group of radio buttons for employment type (Full-time, Part-time, Contract), and a <textarea> for a cover letter. Include a submit button with type="submit" and a reset button with type="reset". Ensure every input has a proper name attribute and the form uses method="POST".

ES
Edrees Salih
17 hours ago

We are still cooking the magic in the way!