Chapter 7 Beginner 25 min min read Updated 2026-04-11

Forms, Inputs, and Form Validation

Practice Questions →

In This Chapter

What Is It?

What Are HTML Forms?

Every time you sign up on a website, log in, send a message, search on Google, order food, or leave a comment — you are using an HTML form. A form is a group of input fields where users can type, select, click, and upload things. When they hit submit, the data is sent to a server for processing.

Forms are the way websites collect information from their users. Without forms, the web would be a one-way street — you could only read, never contribute.

The Anatomy of a Form

A form has three main parts:

  1. The <form> tag — the container that wraps everything. It has an action (where to send the data) and a method (how to send it — GET or POST).
  2. Input fields — places for users to type or select things. <input>, <select>, <textarea>, and more.
  3. A submit button — the button that sends the data when clicked.

Why Does It Matter?

Why Should You Learn HTML Forms?

1. Forms Are Everywhere

Sign-up form, login form, search box, comment section, contact form, shopping checkout, survey, feedback form — every interactive website has forms. If you want to build real web apps, you must know forms.

2. HTML Has Built-in Validation

Modern HTML can check if an email looks valid, if a number is in a range, if a field is empty, if a password is long enough — all without writing a single line of JavaScript. This is called HTML5 validation, and it is one of the best features of modern HTML.

3. Accessibility for Everyone

Properly marked-up forms work for everyone — including users with disabilities. Screen readers read field labels aloud so blind users know what to type. Keyboard users can tab from field to field. Good forms = accessible websites.

4. The Foundation for JavaScript

When you learn JavaScript (in our JavaScript course), you will read form values, validate them with code, and send them to a server. But none of that works if the HTML form is wrong. Forms are the foundation.

Detailed Explanation

Detailed Explanation

The <form> Tag

The <form> tag wraps all your inputs. It has two important attributes:

  • action — the URL where the form data will be sent. Example: action="/signup".
  • method — how to send it. GET adds the data to the URL (for searches). POST sends it hidden in the request body (for sensitive stuff like passwords).
<form action="/signup" method="POST">
  <!-- inputs go here -->
</form>

The <input> Tag and Its Types

The most important form element is <input>. It is a self-closing tag that creates a single input field. What it looks like and what it accepts depends on the type attribute. Here are the most useful types:

  • type="text" — a single-line text field. Default if no type is given.
  • type="email" — like text, but the browser checks for a valid email format (must have @ and a domain).
  • type="password" — hides the typed characters with dots or stars.
  • type="number" — only accepts numbers. Has up/down arrows. Use min, max, and step.
  • type="tel" — for phone numbers. On mobile, it opens the numeric keypad.
  • type="url" — for web addresses. Validates that it looks like a URL.
  • type="date" — a date picker. The browser shows a calendar.
  • type="time" — a time picker with hours and minutes.
  • type="color" — a color picker that opens a color palette.
  • type="range" — a slider. Use with min, max, and step.
  • type="file" — lets users upload a file from their computer.
  • type="hidden" — invisible field for storing extra data to send with the form.
  • type="submit" — the button that submits the form.
  • type="reset" — clears all fields. Rarely useful (users click it by mistake).
  • type="button" — a generic button (usually activated with JavaScript).
  • type="checkbox" — a box users tick. Lets you pick multiple options.
  • type="radio" — a round button. Users pick ONE option from a group.

<label> and Why Accessibility Matters

Every input should have a <label>. A label is the piece of text that tells the user what the field is for — like "Email" or "Password". There are two ways to link a label to its input:

<!-- Method 1: for + id -->
<label for="email">Email:</label>
<input type="email" id="email" name="email">

<!-- Method 2: wrap the input -->
<label>
  Email:
  <input type="email" name="email">
</label>

The for attribute on <label> must match the id on the input. This connection gives you three benefits:

  • Clicking the label focuses the input. Great for mobile users with small fingers — easier to tap a label.
  • Screen readers announce the label. When a blind user tabs to the field, the screen reader says "Email, edit text".
  • Clearer meaning. The label makes the field's purpose obvious.

Never use a placeholder as a label. Placeholders disappear when the user starts typing, confusing users. Always use a real <label>.

<select> and <option> (Dropdowns)

For a dropdown menu where users pick one item from a list, use <select> with <option> tags inside:

<label for="country">Country:</label>
<select id="country" name="country">
  <option value="india">India</option>
  <option value="usa">USA</option>
  <option value="uk">United Kingdom</option>
</select>

The value attribute is what gets sent to the server. The text between the tags is what the user sees. Add selected to one option to make it the default.

<textarea> for Long Text

For multi-line text input (like a comment or bio), use <textarea>. It takes rows and cols attributes, or you can size it with CSS.

<label for="bio">Your Bio:</label>
<textarea id="bio" name="bio" rows="4" cols="30"></textarea>

<fieldset> and <legend> for Grouping

For large forms, group related fields together using <fieldset>. Add a <legend> to give the group a title. Browsers automatically draw a border around fieldsets.

<fieldset>
  <legend>Contact Info</legend>
  <label>Email: <input type="email"></label>
  <label>Phone: <input type="tel"></label>
</fieldset>

HTML5 Validation Attributes

These attributes make the browser validate the form before submitting. No JavaScript needed.

  • required — field cannot be empty. <input required>
  • placeholder — grey hint text inside the field. Disappears when the user types.
  • min / max — for numbers and dates. min="0" max="100"
  • minlength / maxlength — minimum and maximum characters. minlength="8"
  • pattern — a regex the value must match. pattern="[0-9]{10}" for a 10-digit number.
  • readonly — the user cannot change the value, but the form still sends it.
  • disabled — the user cannot change it, AND the form does NOT send it.

name vs id

This confuses beginners. Both are attributes on input fields, but they do different things:

  • name — used when the form is submitted. The server sees the data as name=value. Without name, the data does not get sent.
  • id — used for labels (the for attribute), CSS styling, and JavaScript. It has nothing to do with submitting.

Most fields need both: name for the server, id for the label.

The autocomplete Attribute

Modern browsers can remember what users typed before. The autocomplete attribute controls this. Common values: on, off, name, email, tel, current-password, new-password. For passwords, use current-password on login forms and new-password on sign-up forms.

Code Examples

A Simple Contact Form
<!DOCTYPE html>
<html>
<head>
  <title>Contact Us</title>
  <style>
    body { font-family: Arial; padding: 30px; }
    label { display: block; margin-top: 10px; font-weight: bold; }
    input, textarea { padding: 8px; width: 300px; margin-top: 5px; }
    button { padding: 10px 20px; margin-top: 15px; background: #4a90e2; color: white; border: none; cursor: pointer; }
  </style>
</head>
<body>
  <h1>Contact Modern Age Coders</h1>
  <form action="/submit" method="POST">
    <label for="name">Your Name:</label>
    <input type="text" id="name" name="name" required>

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

    <label for="message">Your Message:</label>
    <textarea id="message" name="message" rows="5" required></textarea>

    <button type="submit">Send Message</button>
  </form>
</body>
</html>
A basic contact form with three fields: name, email, and a message area. Each field has a proper <label> linked by for/id. The required attribute stops the form from submitting if any field is empty. The type="email" makes the browser check that the email has an @ sign. Save as contact.html and open it — try clicking Send with empty fields to see the validation in action.
A styled form with Name, Email, and Message fields. Trying to submit empty shows browser error messages.
A Complete Registration Form with All Input Types
<!DOCTYPE html>
<html>
<head>
  <title>Sign Up</title>
  <style>
    body { font-family: Arial; padding: 20px; max-width: 500px; margin: auto; }
    fieldset { margin-bottom: 15px; border: 1px solid #ccc; padding: 15px; }
    legend { font-weight: bold; padding: 0 8px; }
    label { display: block; margin-top: 8px; }
    input, select, textarea { padding: 6px; width: 100%; box-sizing: border-box; margin-top: 4px; }
    .inline { display: inline; width: auto; margin-right: 5px; }
    button { padding: 10px 20px; background: #22c55e; color: white; border: none; cursor: pointer; margin-top: 10px; }
  </style>
</head>
<body>
  <h1>Create Your Account</h1>
  <form action="/signup" method="POST">
    <fieldset>
      <legend>Personal Info</legend>
      <label for="fullname">Full Name:</label>
      <input type="text" id="fullname" name="fullname" required minlength="3" placeholder="Aarav Sharma">

      <label for="email">Email:</label>
      <input type="email" id="email" name="email" required placeholder="you@example.com" autocomplete="email">

      <label for="password">Password:</label>
      <input type="password" id="password" name="password" required minlength="8" autocomplete="new-password">

      <label for="age">Age:</label>
      <input type="number" id="age" name="age" min="10" max="100" required>
    </fieldset>

    <fieldset>
      <legend>Gender</legend>
      <label><input type="radio" name="gender" value="male" class="inline" required> Male</label>
      <label><input type="radio" name="gender" value="female" class="inline"> Female</label>
      <label><input type="radio" name="gender" value="other" class="inline"> Other</label>
    </fieldset>

    <fieldset>
      <legend>Interests</legend>
      <label><input type="checkbox" name="interests" value="coding" class="inline"> Coding</label>
      <label><input type="checkbox" name="interests" value="maths" class="inline"> Maths</label>
      <label><input type="checkbox" name="interests" value="art" class="inline"> Art</label>
      <label><input type="checkbox" name="interests" value="music" class="inline"> Music</label>
    </fieldset>

    <label for="country">Country:</label>
    <select id="country" name="country" required>
      <option value="">-- Select --</option>
      <option value="in">India</option>
      <option value="us">USA</option>
      <option value="uk">United Kingdom</option>
    </select>

    <label for="bio">Short Bio:</label>
    <textarea id="bio" name="bio" rows="4" maxlength="200" placeholder="Tell us about yourself..."></textarea>

    <button type="submit">Sign Up</button>
  </form>
</body>
</html>
This is a complete, real-world registration form using almost every important input type. Fields are grouped with <fieldset> and <legend>. Text, email, password, and number inputs all have validation. Radio buttons let the user pick ONE gender (notice they share the same name). Checkboxes let the user pick multiple interests. The select is a dropdown for country, and textarea is for the bio. Save as signup.html and try it.
A full sign-up form with grouped sections: Personal Info, Gender, Interests, Country, and Bio. Browser validates each field on submit.
Password Field with minlength and pattern
<!DOCTYPE html>
<html>
<head>
  <title>Secure Password</title>
</head>
<body>
  <h2>Create a Strong Password</h2>
  <form>
    <label for="pwd">Password (at least 8 chars, must contain a digit):</label><br>
    <input type="password" id="pwd" name="pwd"
           minlength="8"
           pattern="(?=.*[0-9]).{8,}"
           title="At least 8 characters and one number"
           required>
    <br><br>
    <button type="submit">Submit</button>
  </form>
</body>
</html>
The pattern attribute uses a regular expression to enforce custom rules. (?=.*[0-9]).{8,} means: must contain at least one digit AND must be 8 or more characters. The title attribute gives an error message to show if validation fails. Save as password.html and try typing only letters — the browser will block submit.
A password field. If you type only letters, the browser shows the 'At least 8 characters and one number' hint when you try to submit.
Number, Range, and Color Inputs
<!DOCTYPE html>
<html>
<head>
  <title>Modern Input Types</title>
  <style>
    body { font-family: Arial; padding: 30px; }
    label { display: block; margin-top: 15px; font-weight: bold; }
    input { padding: 6px; font-size: 16px; }
  </style>
</head>
<body>
  <h1>Cool HTML5 Inputs</h1>
  <form>
    <label for="age">Age (10 to 80):</label>
    <input type="number" id="age" name="age" min="10" max="80" step="1" value="15">

    <label for="volume">Volume (0 to 100):</label>
    <input type="range" id="volume" name="volume" min="0" max="100" value="50">

    <label for="color">Favourite Colour:</label>
    <input type="color" id="color" name="color" value="#ff5722">

    <label for="birth">Date of Birth:</label>
    <input type="date" id="birth" name="birth">

    <label for="alarm">Alarm Time:</label>
    <input type="time" id="alarm" name="alarm">

    <br><br>
    <button type="submit">Submit</button>
  </form>
</body>
</html>
HTML5 gave us specialized input types that work beautifully in modern browsers. type="number" shows spinner arrows and validates numbers. type="range" is a slider. type="color" opens a full color picker. type="date" opens a calendar. type="time" opens a time picker. On mobile phones, these trigger specialized keyboards (number pad, date wheel, etc.) making the experience even better.
A form with a number spinner, a slider, a color picker, a calendar date field, and a time field.
Radio Buttons vs Checkboxes
<!DOCTYPE html>
<html>
<head>
  <title>Radio vs Checkbox</title>
  <style>
    body { font-family: Arial; padding: 30px; }
    fieldset { margin-bottom: 15px; }
    legend { font-weight: bold; }
  </style>
</head>
<body>
  <form>
    <fieldset>
      <legend>Pick your favourite fruit (only one)</legend>
      <label><input type="radio" name="fruit" value="mango"> Mango</label><br>
      <label><input type="radio" name="fruit" value="apple"> Apple</label><br>
      <label><input type="radio" name="fruit" value="banana"> Banana</label>
    </fieldset>

    <fieldset>
      <legend>Which snacks do you like? (pick many)</legend>
      <label><input type="checkbox" name="snacks" value="chips"> Chips</label><br>
      <label><input type="checkbox" name="snacks" value="cookies"> Cookies</label><br>
      <label><input type="checkbox" name="snacks" value="chocolate"> Chocolate</label><br>
      <label><input type="checkbox" name="snacks" value="popcorn"> Popcorn</label>
    </fieldset>

    <button type="submit">Submit</button>
  </form>
</body>
</html>
Radio buttons in a group share the same name. The browser automatically enforces that only ONE can be selected at a time. Checkboxes, on the other hand, can all be selected at once — each represents an independent yes/no choice. Rule of thumb: use radio for "pick one", checkbox for "pick any".
Two groups of options. The fruit radios let you pick only one. The snack checkboxes let you pick as many as you want.
File Upload with Hidden Field
<!DOCTYPE html>
<html>
<head>
  <title>Upload Photo</title>
</head>
<body>
  <h2>Upload a Profile Photo</h2>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <label for="photo">Choose a photo:</label><br>
    <input type="file" id="photo" name="photo" accept="image/*" required>

    <!-- Hidden field for the user ID -->
    <input type="hidden" name="userId" value="12345">

    <br><br>
    <button type="submit">Upload</button>
  </form>
</body>
</html>
File uploads need type="file". The accept attribute restricts what kinds of files show up — image/* means any image, .pdf means only PDFs, etc. The form must have enctype="multipart/form-data" for file uploads to work. Hidden fields (type="hidden") are invisible but still sent with the form — useful for passing data like user IDs or form versions.
A form with a 'Choose file' button that opens the file picker. The hidden userId is sent along with the form but not shown to the user.
Login Form with Labels and Autocomplete
<!DOCTYPE html>
<html>
<head>
  <title>Login</title>
  <style>
    body { font-family: Arial; padding: 40px; background: #f5f5f5; }
    .box { background: white; padding: 30px; max-width: 350px; margin: auto; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
    h1 { text-align: center; }
    label { display: block; margin-top: 15px; font-weight: bold; }
    input { padding: 10px; width: 100%; box-sizing: border-box; margin-top: 5px; border: 1px solid #ccc; border-radius: 5px; }
    button { width: 100%; padding: 12px; margin-top: 20px; background: #4a90e2; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; }
  </style>
</head>
<body>
  <div class="box">
    <h1>Log In</h1>
    <form action="/login" method="POST">
      <label for="email">Email:</label>
      <input type="email" id="email" name="email" required autocomplete="email">

      <label for="password">Password:</label>
      <input type="password" id="password" name="password" required autocomplete="current-password">

      <label><input type="checkbox" name="remember"> Remember me</label>

      <button type="submit">Log In</button>
    </form>
  </div>
</body>
</html>
A simple but complete login form. The email field has autocomplete="email" so the browser can suggest previously entered emails. The password has autocomplete="current-password", which tells password managers to fill in the existing password (for signup, you would use new-password instead). The Remember me is a checkbox. Everything has proper labels.
A clean centered login box with Email, Password, Remember me checkbox, and a Log In button.

Common Mistakes

Forgetting the name Attribute

<form action="/submit" method="POST">
  <input type="text" id="username">
  <button type="submit">Submit</button>
</form>
No error, but the server receives NO data for the username field.
<form action="/submit" method="POST">
  <input type="text" id="username" name="username">
  <button type="submit">Submit</button>
</form>
When a form is submitted, only fields with a name attribute are sent to the server. Without name, the value is simply ignored. The id is for labels, CSS, and JavaScript — it does not count for form submission. Always add name to every field you want to submit.

Using Placeholder Instead of Label

<input type="text" placeholder="Enter your name">
No HTML error, but bad for accessibility. The hint disappears when the user starts typing.
<label for="name">Your Name:</label>
<input type="text" id="name" name="name" placeholder="e.g. Aarav">
Placeholders are hints, not labels. They vanish the moment the user types something, so the user can forget what the field is for. Screen readers often skip placeholders. Always use a real <label>, and use the placeholder only for extra hints like examples.

Different Name on Radio Buttons in the Same Group

<input type="radio" name="gender1" value="male"> Male
<input type="radio" name="gender2" value="female"> Female
<input type="radio" name="gender3" value="other"> Other
No error, but all three radios are selectable at once — they are not grouped.
<input type="radio" name="gender" value="male"> Male
<input type="radio" name="gender" value="female"> Female
<input type="radio" name="gender" value="other"> Other
Radio buttons form a group based on their name. Only radios with the same name are mutually exclusive. If every radio has a different name, they all act independently — which defeats the purpose of radio buttons. Always give all radios in a group the same name.

Missing for/id Connection on Label

<label>Email:</label>
<input type="email" id="email" name="email">
The label is not linked to the input. Clicking the label does NOT focus the input.
<label for="email">Email:</label>
<input type="email" id="email" name="email">
Without for="email", the label is just text floating near the input. The accessibility benefits are lost. Either use for + id, OR wrap the input inside the label. Both work.

Using disabled When You Meant readonly

<input type="text" name="email" value="aarav@example.com" disabled>
No error, but the email is NOT sent when the form submits.
<input type="text" name="email" value="aarav@example.com" readonly>
disabled prevents the user from editing AND excludes the field from the submission. readonly prevents editing but still submits the value. If you want the server to receive the current value (like a pre-filled email that the user cannot change), use readonly.

Summary

  • HTML forms are how websites collect information from users. Every form is wrapped in a <form> tag with action (where to send) and method (GET or POST).
  • The <input> tag is the most used form element. Its type attribute decides what kind of field it is: text, email, password, number, date, color, file, checkbox, radio, and more.
  • Every input should have a <label> linked by for and id, OR the input should be wrapped inside the label. This helps screen readers and lets users click the label to focus the input.
  • name is required for form submission — the server uses it as the key. id is used by labels, CSS, and JavaScript. You usually need both.
  • Radio buttons in the same group must share the same name so only one can be selected. Checkboxes can be selected independently.
  • <select> with <option> tags creates a dropdown. <textarea> creates a multi-line text box. <fieldset> with <legend> groups related fields together.
  • HTML5 validation attributes work without any JavaScript: required, min, max, minlength, maxlength, pattern, placeholder, readonly, disabled.
  • Never use placeholder as a replacement for label. Placeholders disappear when users type, confusing users and breaking accessibility.
  • autocomplete helps browsers suggest previously entered values. Use current-password on login forms and new-password on sign-up forms for password managers.
  • type="file" lets users upload files. Use the accept attribute to restrict file types. The form must have enctype="multipart/form-data" for file uploads.

Ready to Practice?

Test your understanding with 50+ practice questions on this topic.

Go to Practice Questions

Want to learn web development with a live mentor?

Explore our Frontend Masterclass