📝 Lesson 8: Forms & Input
Every login screen, search bar, checkout page, and contact form on the web is built with HTML form elements. Forms are how websites collect information from users — and learning to build them is one of the most practical skills in web development.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Create a form with the
<form>element - Use common input types: text, email, password, number, and more
- Associate labels with inputs using
<label> - Build checkboxes, radio buttons, dropdowns, and textareas
- Group related fields with
<fieldset>and<legend> - Add basic form validation with HTML attributes
Estimated Time: 55 minutes
Hands-on: You'll build a contact form for your website.
📑 In This Lesson
The <form> Element
All form controls (inputs, buttons, dropdowns) live inside a <form> element. The form acts as a container and tells the browser where to send the data when the user submits:
<form action="/submit" method="post">
<!-- form controls go here -->
</form>
The two key attributes:
action— the URL where the form data gets sent (a server endpoint)method— how the data is sent:"get"appends data to the URL (for searches);"post"sends data in the request body (for sensitive data like passwords)
out form"] --> B["User clicks
Submit"] B --> C["Browser packages
form data"] C --> D["Sends to server
at 'action' URL"] D --> E["Server processes
and responds"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b style B fill:#fdf4ff,stroke:#a855f7,stroke-width:2px,color:#1e293b style C fill:#fffbeb,stroke:#f59e0b,stroke-width:2px,color:#1e293b style D fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#1e293b style E fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b
💡 For Now: No Server Required
We're building the HTML side of forms in this lesson — the user interface. Making forms actually do something requires a backend server, which is beyond the scope of this course. For now, your forms will look and feel real but won't send data anywhere. You can use action="#" as a placeholder.
Text Inputs and Labels
The <input> element is the workhorse of forms. Its most basic form creates a single-line text field:
<input type="text" name="username">
But an input by itself is incomplete — the user has no idea what to type in it. That's where <label> comes in:
<label for="username">Username:</label>
<input type="text" id="username" name="username">
The for attribute on the label must match the id attribute on the input. This connection is critical for three reasons:
- Accessibility: Screen readers announce the label when the input is focused
- Usability: Clicking the label text focuses the input field (try it!)
- Semantics: The browser knows these two elements belong together
The name Attribute
Every input needs a name attribute — it's the key that identifies this field's data when the form is submitted. Without a name, the input's value won't be included in the form submission.
<!-- When submitted, the server receives: username=whatever-they-typed -->
<input type="text" id="username" name="username">
Placeholder Text
The placeholder attribute shows a light hint inside the input that disappears when the user starts typing:
<input type="text" id="username" name="username"
placeholder="e.g., alex_johnson">
⚠️ Placeholders Are Not Labels
Never use placeholder as a replacement for <label>. Placeholder text disappears when the user starts typing, leaving them with no indication of what the field is for. It also has poor contrast by design and isn't reliably read by all screen readers. Always use a visible <label>.
Input Types
The type attribute on <input> changes both the appearance and behavior of the field. HTML5 introduced many specialized types that improve the user experience — especially on mobile, where the browser shows the right keyboard:
| Type | What It Does | Mobile Keyboard |
|---|---|---|
text |
Single-line text (default) | Standard |
email |
Email address (validates @ format) | Has @ and . keys |
password |
Hides typed characters with dots | Standard |
number |
Numeric input with up/down arrows | Number pad |
tel |
Phone number | Phone dial pad |
url |
Web address (validates URL format) | Has / and .com keys |
date |
Date picker | Calendar picker |
color |
Color picker | Color palette |
range |
Slider between a min and max value | Drag slider |
search |
Search field (may show clear button) | Has Search key |
<label for="email">Email:</label>
<input type="email" id="email" name="email"
placeholder="you@example.com">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<label for="age">Age:</label>
<input type="number" id="age" name="age" min="1" max="120">
<label for="birthday">Birthday:</label>
<input type="date" id="birthday" name="birthday">
<label for="fav-color">Favorite Color:</label>
<input type="color" id="fav-color" name="fav-color" value="#3b82f6">
💡 Graceful Degradation
If a browser doesn't support a specialized input type (like date on an older browser), it falls back to a plain text input. The form still works — the user just types the date instead of using a picker. This is called graceful degradation.
Checkboxes, Radio Buttons, and Dropdowns
Checkboxes
Checkboxes let users select zero or more options from a set:
<p>Select your interests:</p>
<input type="checkbox" id="html" name="interests" value="html">
<label for="html">HTML</label>
<input type="checkbox" id="css" name="interests" value="css">
<label for="css">CSS</label>
<input type="checkbox" id="js" name="interests" value="javascript">
<label for="js">JavaScript</label>
Notice that all three checkboxes share the same name ("interests") but have different value attributes. The value is what gets sent to the server when that box is checked.
Radio Buttons
Radio buttons let users select exactly one option from a set:
<p>Experience level:</p>
<input type="radio" id="beginner" name="level" value="beginner">
<label for="beginner">Beginner</label>
<input type="radio" id="intermediate" name="level" value="intermediate">
<label for="intermediate">Intermediate</label>
<input type="radio" id="advanced" name="level" value="advanced">
<label for="advanced">Advanced</label>
The key difference from checkboxes: radio buttons with the same name form a group, and only one in the group can be selected at a time. Selecting one automatically deselects the others.
☑ Multiple selections
☑ Independent toggles"] A --> C["Radio Button
◉ One selection only
◉ Grouped by name"] A --> D["Dropdown
▾ One selection
▾ Saves space"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b style B fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#1e293b style C fill:#fdf4ff,stroke:#a855f7,stroke-width:2px,color:#1e293b style D fill:#fffbeb,stroke:#f59e0b,stroke-width:2px,color:#1e293b
Dropdown Menus (<select>)
A dropdown (or "select menu") presents a list of options in a compact space:
<label for="country">Country:</label>
<select id="country" 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>
<option value="au">Australia</option>
</select>
The first <option> with an empty value serves as a placeholder prompt. Each <option> has a value (sent to the server) and display text (shown to the user).
You can group options using <optgroup>:
<select id="language" name="language">
<optgroup label="Frontend">
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
</optgroup>
<optgroup label="Backend">
<option value="python">Python</option>
<option value="java">Java</option>
<option value="csharp">C#</option>
</optgroup>
</select>
Textareas and Buttons
<textarea>
For multi-line text (messages, comments, bios), use <textarea> instead of <input>:
<label for="message">Message:</label>
<textarea id="message" name="message"
rows="5" cols="40"
placeholder="Type your message here..."></textarea>
Unlike <input>, the <textarea> has an opening and closing tag. Any text between the tags becomes the default value. The rows and cols attributes set the initial visible size (though CSS is a better way to control this).
Buttons
There are two ways to create a submit button:
<!-- Method 1: input with type="submit" -->
<input type="submit" value="Send Message">
<!-- Method 2: button element (more flexible) -->
<button type="submit">Send Message</button>
The <button> element is preferred because you can put anything inside it — text, icons, images — while <input type="submit"> can only display text via the value attribute.
Button types:
type="submit"— sends the form data (default for<button>inside a form)type="reset"— clears all form fields back to their default valuestype="button"— does nothing by default (used with JavaScript for custom actions)
Grouping with Fieldset and Legend
When a form has related groups of fields, use <fieldset> and <legend> to organize them:
<form action="#" method="post">
<fieldset>
<legend>Personal Information</legend>
<label for="fname">First Name:</label>
<input type="text" id="fname" name="fname">
<label for="lname">Last Name:</label>
<input type="text" id="lname" name="lname">
<label for="email">Email:</label>
<input type="email" id="email" name="email">
</fieldset>
<fieldset>
<legend>Preferences</legend>
<input type="checkbox" id="newsletter" name="newsletter" value="yes">
<label for="newsletter">Subscribe to newsletter</label>
<input type="checkbox" id="updates" name="updates" value="yes">
<label for="updates">Receive product updates</label>
</fieldset>
<button type="submit">Save</button>
</form>
<fieldset>draws a visual border around the group (which you can style with CSS)<legend>provides a caption that appears embedded in the border
Fieldsets are especially important for radio button groups and checkbox groups — screen readers use the legend to announce what the group of choices is for.
Basic HTML Validation
HTML has built-in attributes that validate form data before it's submitted — no JavaScript required:
<!-- Required: field can't be empty -->
<input type="text" name="username" required>
<!-- Minimum and maximum length -->
<input type="text" name="username"
minlength="3" maxlength="20" required>
<!-- Number range -->
<input type="number" name="age" min="18" max="99">
<!-- Pattern: must match a regular expression -->
<input type="text" name="zipcode"
pattern="[0-9]{5}"
title="Five-digit ZIP code">
| Attribute | What It Does | Works On |
|---|---|---|
required |
Field must be filled in | Most input types, textarea, select |
minlength |
Minimum characters required | text, email, password, textarea |
maxlength |
Maximum characters allowed | text, email, password, textarea |
min / max |
Minimum / maximum numeric value | number, range, date |
pattern |
Must match a regular expression | text, tel, email, url, search |
When validation fails, the browser blocks the form submission and shows a built-in error message near the offending field. The title attribute provides extra context in the error tooltip.
💡 Client-Side vs. Server-Side Validation
HTML validation is convenient and fast, but it's client-side only — a tech-savvy user can bypass it by editing the HTML in DevTools. Real applications always validate data on the server too. Think of HTML validation as a friendly first check, not a security measure.
Hands-on Exercise
🏋️ Exercise: Build a Contact Form
Objective: Create a complete contact form using the elements covered in this lesson.
Instructions:
- In your
my-websitefolder, create a new file calledcontact.html - Use the Emmet shortcut to generate the HTML skeleton
- Set the
<title>to "Contact Me" - Create a
<form>withaction="#"andmethod="post" - Add the following fields (each with a proper
<label>):- Name —
type="text", required - Email —
type="email", required - Subject — a
<select>dropdown with options: General Inquiry, Feedback, Bug Report, Other - Message — a
<textarea>, required, minimum 20 characters
- Name —
- Wrap the Name and Email fields in a
<fieldset>with a<legend>of "Your Info" - Add a
<button type="submit"> - Add a navigation link back to
index.html - Save and test — try submitting the form without filling in required fields
💡 Hint
Make sure every <label> has a for attribute that matches the id of its corresponding input. Don't forget the name attribute on every form control — it's what identifies the data.
✅ Example Solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Me</title>
</head>
<body>
<a href="index.html">Back to Home</a>
<h1>Contact Me</h1>
<p>Have a question or feedback? Fill out the form
below and I'll get back to you.</p>
<form action="#" method="post">
<fieldset>
<legend>Your Info</legend>
<label for="name">Name:</label><br>
<input type="text" id="name" name="name"
required><br><br>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email"
required placeholder="you@example.com">
</fieldset>
<br>
<label for="subject">Subject:</label><br>
<select id="subject" name="subject">
<option value="">-- Choose a subject --</option>
<option value="general">General Inquiry</option>
<option value="feedback">Feedback</option>
<option value="bug">Bug Report</option>
<option value="other">Other</option>
</select><br><br>
<label for="message">Message:</label><br>
<textarea id="message" name="message"
rows="6" cols="40"
minlength="20" required
placeholder="Write at least 20 characters..."></textarea>
<br><br>
<button type="submit">Send Message</button>
</form>
</body>
</html>
🎯 Quick Quiz
Question 1: Why must every input have a <label>?
Question 2: What's the difference between checkboxes and radio buttons?
Question 3: Which attribute makes a field mandatory?
Question 4: Why is <button> preferred over <input type="submit">?
Summary
🎉 Key Takeaways
- The
<form>element wraps all form controls;actionsets where data is sent,methodsets how - Always pair
<input>elements with<label>using matchingfor/idattributes - Every form control needs a
nameattribute — it's the key for the submitted data - HTML5 input types (
email,number,date, etc.) improve UX by showing the right keyboard and providing built-in validation - Checkboxes allow multiple selections; radio buttons (with the same
name) allow only one <select>creates dropdowns;<textarea>creates multi-line text fields<fieldset>and<legend>group related fields and improve accessibility- HTML validation attributes (
required,minlength,pattern, etc.) provide a first layer of data checking
📁 Your Project So Far
my-website/
├── images/
│ └── sunset.jpg
├── index.html
├── about.html
├── recipe.html
└── contact.html ← new in this lesson
🚀 What's Next?
You've now learned every fundamental HTML element you need for a real website — text, links, images, lists, tables, and forms. But there's one more critical concept before we move on to CSS: semantic HTML. In the next lesson, you'll learn how to use elements like <header>, <nav>, <main>, <article>, and <footer> to give your page meaning and structure that goes far beyond plain <div> tags.