Skip to main content
Back to module
HTML & CSS Foundations · Semantic HTML

Forms and inputs

Reading44mLesson 4 of 4 in this module

What you'll learn

  • Build a labelled form with validation attributes
  • Pick input types that match the data being collected
  • Group related radio buttons with fieldset and legend
  • Explain why browser validation does not replace server checks

Build a labelled, accessible form with the right input types and built-in validation.

Why this matters

Forms are how people talk back to a website: sign-ups, searches, checkouts, contact messages, surveys. A badly built form loses customers and locks out keyboard and screen reader users. A well-built one does a lot of work for free: the right keyboard appears on phones, the browser fills in known details, and simple mistakes are caught before anything is sent.

The form element

HTML
<form action="/subscribe" method="post">
  ...controls...
  <button type="submit">Subscribe</button>
</form>
  • action is the URL the data is sent to. On a static site without a server you will often use a third-party form service, or handle the data with JavaScript later.
  • method is get (data goes in the URL query, good for searches) or post (data goes in the request body, right for anything that creates or changes something).
  • Each control's name attribute becomes the key in the submitted data: email=sam%40example.com. A control without a name is not submitted at all.

Labels, always

Every control needs a label, exactly as in the accessibility lesson:

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

The autocomplete attribute tells the browser what the field is (name, email, tel, street-address, new-password and more) so it can offer to fill it in.

Pick the right input type

TypeGives you
texta plain single-line field
emailan email keyboard on phones, and format checking
passwordhidden characters
tela phone keypad (no format checking, because phone formats vary)
numbera numeric field with min, max and step
urlURL keyboard and format checking
datea date picker
checkboxan on/off choice
radioone choice out of a group

For longer text, use <textarea>. For a choice from a long list, use <select> with <option> elements.

Groups: fieldset and legend

Radio buttons that belong together share a name, and the group gets a <fieldset> with a <legend> that acts as the group's label:

HTML
<fieldset>
  <legend>Preferred contact method</legend>
  <label><input type="radio" name="contact" value="email" checked> Email</label>
  <label><input type="radio" name="contact" value="phone"> Phone</label>
</fieldset>

A screen reader announces "Preferred contact method, group" and then "Email, radio button, 1 of 2". Here each input is wrapped inside its label, which connects them without needing for and id.

Built-in validation

HTML can check many rules before the form is sent, with no JavaScript:

HTML
<input type="email" name="email" required>
<input type="number" name="age" min="13" max="120">
<textarea name="message" minlength="20" maxlength="500" required></textarea>
<input type="text" name="postcode" pattern="[0-9]{5}" title="Five digits">
  • required: the field must not be empty.
  • minlength / maxlength: limits on text length.
  • min / max / step: limits on numbers and dates.
  • pattern: a regular expression the value must match.

If a rule fails, the browser blocks the submission and shows a message next to the first invalid field. CSS can style invalid fields with the :invalid and :user-invalid pseudo-classes.

Important: browser validation helps the honest user. It is not security. Anyone can bypass it, so the server must always check the data again.

Buttons

<button type="submit"> sends the form; <button type="button"> does nothing by default (for JavaScript actions). A <button> inside a form with no type is a submit button, which surprises people, so always write the type. The button text should say what happens: "Create account", not "Submit".

Worked example: a newsletter sign-up

HTML
<form action="/subscribe" method="post">
  <p>
    <label for="nl-email">Email address</label>
    <input type="email" id="nl-email" name="email" autocomplete="email" required>
  </p>
  <p>
    <label>
      <input type="checkbox" name="weekly" value="yes">
      Send me the weekly digest
    </label>
  </p>
  <button type="submit">Subscribe</button>
</form>

Try submitting it empty: the browser stops you and points at the email field. Type sam@ and try again: it explains the format problem. You wrote no JavaScript.

Common mistakes

  • Placeholders as labels.
  • Forgetting name, so the value is never sent.
  • Radio buttons with different names, which lets the user select all of them.
  • Using type="text" for everything, losing phone keyboards and free checks.
  • Trusting client-side validation as if it were security.

Quick recap

  • <form> with action, method; each control needs a name and a label.
  • Choose input types that match the data; group radios with <fieldset> and <legend>.
  • required, minlength, min, max and pattern give free validation; the server still checks.
  • Always set the button type and write clear button text.

Try it

Open the Do tab and rebuild a club sign-up form that currently relies on placeholders and fake buttons.

Key terms (6)

action
The form attribute giving the URL the form data is sent to.
name
The control attribute that becomes the key for its value in the submitted data; controls without one are not sent.
autocomplete
An attribute telling the browser what a field holds, such as email or name, so it can offer to fill it in.
fieldset
An element that groups related controls, such as a set of radio buttons, with a legend acting as the group's label.
required
A boolean attribute that stops the form from submitting while the field is empty.
pattern
An attribute holding a regular expression that the field's value must match before the form can submit.

Recap

  • A form has an action and a method; every control needs a name and a label.
  • Input types such as email, tel and number give the right phone keyboard and free checks.
  • Radios share one name and sit in a fieldset with a legend.
  • required, minlength, min, max and pattern validate in the browser, but the server must check again.
  • Always set the button type and write button text that says what happens.
Also in this lesson: