Code of the Day
BeginnerThe Document

Forms and Inputs

Forms are the web's primary mechanism for collecting user input — built from semantic elements that tell the browser (and assistive tech) exactly what each field is.

Web FoundationsBeginner8 min read
By the end of this lesson you will be able to:
  • Build a basic HTML form with the correct semantic structure
  • Pair every input with a <label> using the for/id relationship
  • Choose appropriate type attribute values for different kinds of input
  • Understand what action and method on <form> do (without needing a server yet)

Almost everything interactive on the web that collects information from a user goes through an : search boxes, login screens, checkout flows, comment sections. Before JavaScript frameworks and custom inputs, the form was the only mechanism. Understanding it from the HTML level means you understand all of those patterns at their foundation.

The form element

<form> wraps a set of controls and defines what happens when they are submitted. Two attributes control the submission:

  • action — the URL the browser sends the data to. If omitted, the form submits to the current page's URL.
  • method — how the data is sent. GET appends data to the URL as a query string; POST sends it in the request body (invisible in the URL and suitable for sensitive data).
<form action="/search" method="GET">
  <input type="text" name="query">
  <button type="submit">Search</button>
</form>

Submitting this form with "sourdough" in the box navigates to /search?query=sourdough. That is why search forms use GET — the URL is shareable and bookmarkable.

A login form, by contrast, should use POST so the password is not exposed in the URL or browser history:

<form action="/login" method="POST">

</form>

You do not need a server to experiment with forms. Omit the action attribute and the form submits to itself — you will see the query string appear in the address bar. That is enough to understand GET behaviour while learning.

Labels and inputs

Every user-facing control needs a . The <label> element names a field and links to its input via matching for and id values:

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

When the for attribute on <label> matches the id on the <input>:

  1. Clicking the label focuses the input — a larger click target, especially useful on mobile.
  2. Screen readers announce the label text when the user moves to the input.
  3. Browsers can show better mobile keyboards (e.g. the email keyboard for type="email").

Never use placeholder as a substitute for a label. Placeholder text disappears as soon as the user starts typing, leaving them with no reminder of what the field was for.

Input types

The type attribute on <input> does most of the heavy lifting. The browser validates, formats, and picks the right keyboard automatically:

<!-- Free text -->
<input type="text" id="name" name="name">

<!-- Email — validates format, shows @ keyboard on mobile -->
<input type="email" id="email" name="email">

<!-- Password — masks characters -->
<input type="password" id="password" name="password">

<!-- Number — numeric keyboard, min/max/step validation -->
<input type="number" id="age" name="age" min="0" max="120">

<!-- Checkbox — checked or unchecked -->
<input type="checkbox" id="subscribe" name="subscribe">

<!-- Radio — one of a group (all share the same name) -->
<input type="radio" id="size-s" name="size" value="S">
<input type="radio" id="size-m" name="size" value="M">
<input type="radio" id="size-l" name="size" value="L">

<!-- Submit button — clicking it submits the form -->
<input type="submit" value="Send">

Radio buttons need a label for each option and should be wrapped in a <fieldset> with a <legend> to give the group a name:

<fieldset>
  <legend>T-shirt size</legend>

  <label for="size-s">Small</label>
  <input type="radio" id="size-s" name="size" value="S">

  <label for="size-m">Medium</label>
  <input type="radio" id="size-m" name="size" value="M">

  <label for="size-l">Large</label>
  <input type="radio" id="size-l" name="size" value="L">
</fieldset>

<fieldset> groups related controls; <legend> is the label for the group. Screen readers announce the legend before each control inside the fieldset.

Multi-line text and dropdowns

Two more controls that appear in nearly every form:

<textarea> — multi-line text input. Unlike <input>, it has a closing tag and can contain a default value as content:

<label for="message">Message</label>
<textarea id="message" name="message" rows="5" cols="40">
Default text here if needed.
</textarea>

<select> and <option> — a dropdown menu:

<label for="country">Country</label>
<select id="country" name="country">
  <option value="">-- Please select --</option>
  <option value="us">United States</option>
  <option value="gb">United Kingdom</option>
  <option value="ca">Canada</option>
</select>

The value on each <option> is what gets sent with the form; the text inside is what the user sees. An empty value on the placeholder option ensures the user is forced to make a real selection if the field is required.

Button types

<button> is more flexible than <input type="submit">:

<!-- Submits the form -->
<button type="submit">Sign up</button>

<!-- Does nothing on its own — useful for JS-driven actions -->
<button type="button">Preview</button>

<!-- Clears all fields back to their defaults -->
<button type="reset">Clear form</button>

Always set type on a <button> inside a form. The default is type="submit", which means a "Preview" button with no type attribute will accidentally submit the form.

Required fields

The required attribute prevents form submission if the field is empty:

<label for="email">Email address <span aria-hidden="true">*</span></label>
<input type="email" id="email" name="email" required>

The asterisk is a visual convention for "required." Marking it aria-hidden="true" tells screen readers to ignore it — the required attribute on the input already communicates that the field is mandatory through assistive technology.

A complete example

<form action="/signup" method="POST">
  <div>
    <label for="fullname">Full name</label>
    <input type="text" id="fullname" name="fullname" required>
  </div>

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

  <div>
    <label for="password">Password</label>
    <input type="password" id="password" name="password" required>
  </div>

  <div>
    <label for="bio">Short bio (optional)</label>
    <textarea id="bio" name="bio" rows="3"></textarea>
  </div>

  <div>
    <input type="checkbox" id="terms" name="terms" required>
    <label for="terms">I agree to the terms of service</label>
  </div>

  <button type="submit">Create account</button>
</form>

Where to go next

You have the full vocabulary of the HTML document — structure, semantics, attributes, links, images, and forms. The Lab: Build a Well-Structured Page puts all of it together into a realistic exercise where you mark up a complete page from a content brief.

Finished reading? Mark it complete to track your progress.

On this page