2025-09-30

Semantic HTML - Forms

What is the best way to create a semantically correct HTML form? In this blog I will explain what HTML elements to use, and some of the best practices to make a semantically correct and accessible form.

Let's start with a list of elements to use when creating a form.

<form>This is the container element when creating a form.
<fieldset>This element should be used to group related form content.
<legend>A fieldset needs a legend. A legend describes the content within a fieldset.
<label>An input field always needs to be connected with a label. You can connect a label with an input with the 'for' attribute. The value of 'for' has to be the same as the 'id' of the input element.
<input>This is the element where users can provide input. To determine which input a user has to provide, you have to add the 'type' attribute. There are many different types of input like 'text', 'date' and 'number' etc. 
<textarea>Textarea can be used instead of an input element when you would like to have a bigger inputfield. A textarea also needs to be connected to a label element.
<select>A select element should be used when you would like to display a list of options where users can choose from. A select element also needs to be connected to a label element. When using select you need 'option' elements to define the options to choose from.
<option>Option elements should be used to define the options within a select. The 'value' attribute defines the value of the option.
<optgroup> With optgroup you could group options within a select together.


A form could have multiple fieldsets to group together parts of the form that are related. For example, there could be a fieldset with personal information, and another fieldset for services you would like to receive.

It is possible to nest an input within a label element. This could be beneficial for styling (you won't need a div). When doing so, officially you don't need to connect the label with 'for' to the input's id because the input is nested within the label. But it is still a best practice to connect the label with 'for' to the input's id.

Don't forget to check for valid input and give users suggestions where possible if the given input isn't right. Also give statusmessages after submitting the form. When you use a '*' next to a label to communicate that the form input is required, always give an explaination somewhere close to the form what the '*' means. For example above the form: 'Fields with '*' are required.'. This is important for the accessibility, and even required according to the European accessibility act. It is also good to remember that when you want to give extra information to a label with the 'aria-label' attribute, that the value you give to aria-label starts the same as the visible text within the label.

Example of a semantically correct HTML form

<form action="/submit" method="post">
    <fieldset>
      <legend>Personal Information</legend>

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

      <label for="email">
            Email Address
            <input type="email" id="email" name="email" required>
      </label>

      <label for="phone">
             Phone Number
             <input type="tel" id="phone" name="phone">
      </label>
    </fieldset>

    <fieldset>
      <legend>Service</legend>

      <label for="service">Choose a service</label>
      <select id="service" name="service" required>
        <option value="" disabled hidden selected>-- Please choose --</option>
        <option value="firstservice">First service</option>
        <option value="secondservice">Second service</option>
      </select>

      <label for="newsletter">
        Subscribe to newsletter
        <input type="checkbox" id="newsletter" name="newsletter">
      </label>
    </fieldset>

    <fieldset>
      <legend>Message</legend>

     <label for="title">
            Title
            <input type="text" id="title" name="title" required>
      </label>
      <label for="message">
            Message
            <textarea id="message" name="message" rows="6" required></textarea>
      </label>
    </fieldset>

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

Interesting sources

Go back to blogs