Skip to main content

📝 Forms and Input Types

Every time you log in, sign up, search, or check out, you're using a form. Forms are how the web listens — the two-way door between a visitor and your application. Master them here and you'll have the raw material that every interactive feature, and later every back-end route, is built to receive.

Week 1 · Day 2 (Tuesday: HTML Fundamentals) · Lecture 3

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Build a <form> and set its action and method correctly
  • Explain the practical differences between GET and POST
  • Choose the right <input> type for text, numbers, dates, files, and choices
  • Use <textarea>, <select>, and <datalist> for richer controls
  • Associate every control with a <label> and group fields with <fieldset>
  • Apply built-in HTML5 validation with required, pattern, and type-specific rules

Estimated Time: 65 minutes

Practice: Build an accessible, validated sign-up form from scratch.

In This Lesson

How a Form Works

A form is a digital version of a paper form. The user fills in fields, hits a submit button, and the browser bundles up all the answers and sends them somewhere — usually a server — which processes them and sends back a response. Understanding that round trip makes every attribute below click into place.

sequenceDiagram participant User participant Browser participant Server User->>Browser: Fills out the fields User->>Browser: Clicks Submit Browser->>Browser: Validates (HTML5 rules) Browser->>Server: Sends the form data Server->>Server: Processes the data Server->>Browser: Returns a response Browser->>User: Shows the result

For now everything happens in the browser — later in the bootcamp your own Node.js server will be the thing on the right receiving that data. The HTML you write here is the contract for what gets sent.

The Form Element

The <form> element is the envelope that holds all the controls and knows where to mail them. Two attributes do the heavy lifting: action (the destination URL) and method (how to send the data).

<form action="/submit-form" method="post">
    <!-- All the inputs, labels, and the submit button go here -->
</form>

Key form attributes

AttributePurposeExample
actionURL that receives the dataaction="/submit"
methodHow to send it — get or postmethod="post"
enctypeHow data is encoded (needed for file uploads)enctype="multipart/form-data"
novalidateTurns off the browser's built-in validationnovalidate
autocompleteHints whether the browser may autofillautocomplete="on"

💡 The name attribute is what gets sent

Each control's name becomes the key in the submitted data. An input with name="email" and a typed value of a@b.com is sent as email=a@b.com. A control with no name is not submitted at all — a classic "why is my field missing?" bug.

GET vs. POST

The method attribute picks one of two ways to transmit the data, and the choice has real consequences.

graph TD A[method] --> B[GET] A --> C[POST] B --> D[Data goes in the URL] B --> E[Bookmarkable & shareable] B --> F[Good for searches & filters] C --> G[Data goes in the request body] C --> H[Not shown in the URL] C --> I[Good for logins & sign-ups]
  • GET appends the data to the URL as a query string (?q=shoes&size=10). That makes results bookmarkable and shareable — perfect for a search or a filter — but visible in the address bar and browser history, so never use it for passwords.
  • POST tucks the data into the request body, out of the URL. Use it whenever data changes something on the server or is sensitive: logins, sign-ups, posting a comment, uploading a file.
💡 Quick rule: If submitting the form reads data (a search), reach for GET. If it writes or changes data (creating an account), reach for POST.

Input Types

The single <input> element shape-shifts based on its type. HTML5 added a rich set of types that bring the right on-screen keyboard on mobile and free validation. Think of them as specialized tools — reach for the one that fits the data.

Text-based inputs

<input type="text"     name="username" placeholder="Enter username">
<input type="password" name="password" placeholder="Enter password">
<input type="email"    name="email"    placeholder="you@example.com">
<input type="url"      name="website"  placeholder="https://example.com">
<input type="search"   name="query"    placeholder="Search...">
<input type="tel"      name="phone"    placeholder="555-123-4567">

Using type="email" instead of plain text gives you free format checking and pops up the "@"-friendly keyboard on phones. Small choice, big usability win.

Numeric inputs

<!-- A number field with bounds and step size -->
<input type="number" name="age" min="0" max="120" step="1">

<!-- A slider -->
<input type="range" name="volume" min="0" max="100" step="10" value="50">

Date and time inputs

<input type="date"           name="birthday">
<input type="time"           name="appointment">
<input type="datetime-local" name="meeting">
<input type="month"          name="expiry">

Color and file inputs

<input type="color" name="theme" value="#3b82f6">

<!-- Accept only images -->
<input type="file" name="avatar" accept="image/*">

<!-- Accept several documents at once -->
<input type="file" name="docs" multiple accept=".pdf,.doc,.docx">

Choices: checkboxes and radio buttons

The rule that catches everyone: checkboxes allow multiple selections; radio buttons in the same group allow exactly one. Radios are grouped by sharing the same name.

<!-- Checkboxes: pick any number -->
<input type="checkbox" id="coding" name="interests" value="coding">
<label for="coding">Coding</label>

<input type="checkbox" id="design" name="interests" value="design">
<label for="design">Design</label>

<!-- Radios: same name = pick exactly one -->
<input type="radio" id="plan-free" name="plan" value="free" checked>
<label for="plan-free">Free</label>

<input type="radio" id="plan-pro" name="plan" value="pro">
<label for="plan-pro">Pro</label>

Other Form Controls

Textarea — multi-line text

<textarea name="message" rows="5" placeholder="Your message..."></textarea>
💡 Note: Unlike <input>, a <textarea> has a separate closing tag, and any text between the tags becomes its default content. Keep it empty unless you want pre-filled text.

Select — a dropdown

<select name="country">
    <option value="">Select a country</option>
    <option value="us">United States</option>
    <option value="ca">Canada</option>
    <option value="uk">United Kingdom</option>
</select>

<!-- Group options with optgroup -->
<select name="food">
    <optgroup label="Fruits">
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
    </optgroup>
    <optgroup label="Vegetables">
        <option value="carrot">Carrot</option>
    </optgroup>
</select>

Datalist — free text with suggestions

A <datalist> gives an input a list of suggestions while still allowing any typed value — the best of a dropdown and a text field.

<label for="browser">Favorite browser:</label>
<input list="browsers" id="browser" name="browser">
<datalist id="browsers">
    <option value="Chrome"></option>
    <option value="Firefox"></option>
    <option value="Safari"></option>
    <option value="Edge"></option>
</datalist>

Buttons

<button type="submit">Submit</button>   <!-- sends the form -->
<button type="reset">Reset</button>      <!-- clears the fields -->
<button type="button">Click me</button>  <!-- no default action; for JS -->

⚠️ Always set the button type

A <button> with no type defaults to type="submit". So a stray button inside a form can submit it unexpectedly. When a button isn't meant to submit, write type="button" explicitly.

Labels & Accessibility

A form control without a <label> is a usability failure. Labels tell screen-reader users what each field is for, and — a lovely bonus — clicking a label focuses (or toggles) its control, giving checkboxes and radios a much bigger tap target.

Two ways to connect a label

<!-- Explicit: for="id" matches the input's id (preferred) -->
<label for="email">Email:</label>
<input type="email" id="email" name="email">

<!-- Implicit: wrap the input inside the label -->
<label>
    Username:
    <input type="text" name="username">
</label>

⚠️ A placeholder is not a label

Placeholder text vanishes the moment a user starts typing, and many screen readers ignore it. Never use a placeholder instead of a label — use it only as a supplementary hint, if at all.

Fieldset and legend — grouping related fields

Wrap a set of related controls in a <fieldset> and give the group a caption with <legend>. This is especially important for radio groups, where the legend supplies the question the options answer.

<fieldset>
    <legend>Shipping speed</legend>

    <input type="radio" id="std" name="speed" value="standard" checked>
    <label for="std">Standard (5 days)</label>

    <input type="radio" id="exp" name="speed" value="express">
    <label for="exp">Express (2 days)</label>
</fieldset>

Built-in Validation

HTML5 can validate many fields before the form is ever submitted — no JavaScript required. It's like a spell-checker for input: the browser blocks submission and shows a message if a rule is broken.

graph TD A[HTML5 validation] --> B[required] A --> C[type=email / url] A --> D[min / max] A --> E[minlength / maxlength] A --> F[pattern] B --> B1[Field can't be empty] C --> C1[Format is checked] D --> D1[Numeric & date range] E --> E1[Text length limits] F --> F1[Custom regex rule]

Required fields

<input type="text"  name="username" required>
<input type="email" name="email"    required>

Length and range limits

<input type="text"   name="username" minlength="3" maxlength="20">
<input type="number" name="age"      min="18" max="100">
<input type="date"   name="start"    min="2026-01-01" max="2026-12-31">

Pattern validation with a regular expression

The pattern attribute checks the value against a regular expression. Always pair it with a title that explains the rule, since that text is shown when validation fails.

<!-- A US-style phone number: 555-123-4567 -->
<input type="tel"
       name="phone"
       pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
       title="Format: 555-123-4567"
       placeholder="555-123-4567">

⚠️ Client-side validation is convenience, not security

Built-in validation improves the user's experience, but it can be bypassed by anyone who edits the page or sends a request directly. Always validate again on the server. You'll learn exactly how when we build back-end routes later in the course.

A Complete Form

Here's everything from this lesson working together — a login form that's accessible, uses the right input types, and validates before submitting.

<form action="/login" method="post">
    <h2>Log in</h2>

    <div>
        <label for="login-email">Email</label>
        <input type="email" id="login-email" name="email" required autofocus>
    </div>

    <div>
        <label for="login-password">Password</label>
        <input type="password" id="login-password" name="password"
               minlength="8" required>
    </div>

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

    <button type="submit">Log in</button>
    <a href="/forgot-password">Forgot password?</a>
</form>

Read it top to bottom: a post method (it's a login), labelled inputs tied by for/id, the right types (email, password), required and minlength validation, and autofocus so the cursor lands in the first field on load.

Practice & Quiz

🏋️ Exercise: An accessible sign-up form

Goal: Build a sign-up <form> that posts to /register and collects a full name (required), an email (required, correct type), a password (required, at least 8 characters), and a "subscribe to newsletter" checkbox. Every field must have a properly associated <label>, and there must be a submit button.

💡 Hint

Use method="post". Connect each label with for="..." matching each input's id. Use type="email" and type="password", add required to the three mandatory fields, and minlength="8" on the password.

✅ Solution
<form action="/register" method="post">
    <h2>Create your account</h2>

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

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

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

    <div>
        <input type="checkbox" id="news" name="newsletter">
        <label for="news">Subscribe to the newsletter</label>
    </div>

    <button type="submit">Sign up</button>
</form>

Try leaving the email blank and hitting Sign up — the browser blocks submission and points at the empty required field, all with zero JavaScript.

🎯 Quick Quiz

Question 1: You're building a login form. Which method should the form use?

Question 2: A user must pick exactly one shipping option from three. Which control fits?

Question 3: Why is client-side HTML5 validation not enough on its own?

Best Practices & Pitfalls

✅ Do

  • Give every control a real <label>, connected by for/id
  • Pick the most specific input type (email, tel, date) for better keyboards and free validation
  • Group related fields with <fieldset> and a <legend>
  • Use POST for anything sensitive or that changes data; GET for searches
  • Always give <button> an explicit type

❌ Don't

  • Use a placeholder as a substitute for a label
  • Forget the name attribute — nameless controls aren't submitted
  • Send passwords or private data with GET
  • Trust client-side validation as your only line of defense
  • Build one giant, intimidating form when a few grouped sections would do

✅ Autocomplete is a courtesy

Add autocomplete hints like autocomplete="email" or autocomplete="given-name" so browsers can safely autofill known fields. It saves users real typing — especially on mobile.

Summary

🎉 Key Takeaways

  • A <form> bundles controls and sends them to its action using its method
  • GET puts data in the URL (searches); POST hides it in the body (logins, sign-ups)
  • Pick the right input type for better keyboards, pickers, and free validation
  • Every control needs a name to be submitted and a <label> to be accessible
  • HTML5 validation (required, pattern, min/max) helps users — but the server must validate too

📚 Additional Resources

🚀 What's Next?

You've finished the HTML half of Week 1 — you can now structure, describe, and collect. It's time to make it beautiful. The next lesson opens the world of styling with CSS syntax and selectors: how to target elements and change how they look.

📝 Your pages can listen now!

Structure, meaning, and interaction — the full HTML toolkit is yours. Next stop: making it all look great with CSS.