Lesson 31: HTML Forms — Collecting Input from Users
Lesson 31: HTML Forms — Collecting Input from Users
Lesson Introduction
Almost every useful website in the world has a form. When you log in to your email, you fill in a form. When you sign up for a new account, you fill in a form. When you search on Google, you type into a form. When you place an online order, you fill in your address in a form.
Forms are how websites collect information from users.
Without forms, websites can only show information — they cannot receive any. Forms are what turn a one-way display page into a two-way interactive experience.
In this lesson, you will learn everything about HTML forms from the ground up. You will learn how to create text boxes, password fields, checkboxes, radio buttons, drop-down menus, file uploaders, submit buttons, and much more. You will also learn how to use form attributes and input attributes to control exactly how forms behave.
By the end of this lesson, you will be able to build real, complete, professional-looking forms for any purpose — registration, login, surveys, contact pages, and more.
Prerequisite Concepts
Before we start, let’s make sure you understand a few important ideas that will appear throughout this lesson.
What is a “Server”?
When a form is submitted, where does the data go? It goes to a server — a computer that is always running and waiting to receive data. The server is usually running a programming language like PHP, Python, or Node.js that processes the form data (for example, saving it to a database or sending an email).
In this lesson, we focus on the HTML side of forms — building the form itself. You do not need a server to practise. You can simply observe how forms work in the browser.
What Does “Submit” Mean?
Submitting a form means sending the form data somewhere. When you click a “Submit” or “Send” button on a form, the browser collects all the data the user typed or selected and sends it to a destination (usually a server).
What is an “Attribute”?
An attribute is extra information added inside an HTML opening tag to control how the element behaves. For example:
<input type="text" name="username" placeholder="Enter your name">
Here, type, name, and placeholder are all attributes of the <input> element. Each one changes how the input field works.
Part 1: The <form> Element — The Container for Everything
What is the <form> Element?
The <form> element is the container that wraps around all the inputs, labels, and buttons in your form. Just like <ul> contains list items, <form> contains all the fields the user will interact with.
Analogy: Think of the <form> element as an envelope. The envelope itself does not contain any message yet — but it is the container that will hold everything and be addressed (to a server) before being sent.
The Basic <form> Structure
<form action="/submit-page.php" method="post">
<!-- Form fields go here -->
</form>
Every important detail is in the opening tag. Let’s look at the two most important attributes:
The action Attribute
The action attribute tells the browser where to send the form data when the form is submitted.
<form action="/submit-page.php">
- The value is a URL or a file path.
- When the user clicks Submit, the browser navigates to
/submit-page.phpand sends all the form data there. - If you leave
actionout or set it to"", the form data is sent to the same page the form is on.
<!-- Sends data to a specific page -->
<form action="/register.php">
<!-- Sends data to itself (same page) -->
<form action="">
The method Attribute
The method attribute tells the browser how to send the data. There are two options: GET and POST.
| Method | What it does | When to use it |
|---|---|---|
GET |
Sends data as part of the URL (visible in the browser address bar) | For search forms, filters, anything non-sensitive |
POST |
Sends data hidden inside the request body (not visible in the URL) | For passwords, personal info, registrations, anything sensitive |
Example of GET — data visible in URL:
<form action="/search" method="get">
<input type="text" name="query">
<button type="submit">Search</button>
</form>
After submitting with the word “cats”, the URL becomes: /search?query=cats
Example of POST — data hidden:
<form action="/login" method="post">
<input type="password" name="password">
<button type="submit">Login</button>
</form>
The password is NOT visible in the URL. It is sent securely inside the request.
Rule of thumb: Always use
method="post"for anything that involves personal information, passwords, or financial data. Usemethod="get"only for non-sensitive things like search queries.
The target Attribute
The target attribute controls where the response page (the page after the form is submitted) opens.
| Value | What it does |
|---|---|
_self |
Opens in the same tab (default behaviour) |
_blank |
Opens in a new tab |
_parent |
Opens in the parent frame |
_top |
Opens in the full body of the window |
<form action="/result.php" method="post" target="_blank">
<!-- Opens the result in a new tab -->
</form>
The autocomplete Attribute
The autocomplete attribute controls whether the browser should suggest previously typed values when a user starts typing in a field.
<form action="/register.php" method="post" autocomplete="on">
<!-- Browser may suggest saved names, emails, etc. -->
</form>
<form action="/login.php" method="post" autocomplete="off">
<!-- Browser will NOT suggest saved values (useful for security) -->
</form>
The novalidate Attribute
By default, the browser will check form inputs before submitting (for example, making sure an email field contains @). The novalidate attribute turns off this automatic checking.
<form action="/process.php" method="post" novalidate>
<!-- Browser skips built-in validation -->
</form>
Simple Example 1 — A Minimal Form
<!DOCTYPE html>
<html>
<head>
<title>My First Form</title>
</head>
<body>
<h2>Contact Us</h2>
<form action="/send-message.php" method="post">
<!-- Inputs will go here -->
<p>Form fields will appear here.</p>
<button type="submit">Send</button>
</form>
</body>
</html>
Expected Output: A heading “Contact Us”, a paragraph of text, and a “Send” button visible on the page.
Part 2: The <input> Element — The Most Important Form Element
What is <input>?
<input> is the most versatile HTML element. It can create many different types of form fields — text boxes, password fields, checkboxes, radio buttons, file uploaders, date pickers, colour pickers, and more — all depending on the value of its type attribute.
<input> is a self-closing element — it has no closing tag:
<input type="text" name="username">
The type attribute determines what kind of input field is displayed.
Part 3: The <label> Element — Naming Your Fields
Before we look at all the input types, you must understand the <label> element. Every input field should have a label — a visible text description that tells the user what to type.
Why Use <label>?
- It makes forms accessible (screen readers can read labels aloud for visually impaired users).
- Clicking a label automatically focuses (activates) its associated input field — great for usability.
- It makes the form readable and understandable.
How to Connect a <label> to an <input>
Use the for attribute on the label and the id attribute on the input. They must match:
<label for="username">Username:</label>
<input type="text" id="username" name="username">
for="username"— This label belongs to the input withid="username".id="username"— The unique ID of this input field.name="username"— The name used when sending data to the server (the “key” in the key-value pair).
Expected Output: The text “Username:” appears next to a text input box. Clicking the word “Username:” moves the cursor into the input box.
Important difference —
idvsname:
idis used to connect the label to the input inside the HTML page.nameis the key sent to the server. For example, ifname="username"and the user types “Chidi”, the server receivesusername=Chidi.
Part 4: All Input Types
Now let’s go through every input type systematically.
type="text" — Single-line Text Input
The most basic input. Creates a single-line text box.
<form>
<label for="fname">First Name:</label><br>
<input type="text" id="fname" name="firstname"><br>
<label for="lname">Last Name:</label><br>
<input type="text" id="lname" name="lastname">
</form>
Expected Output: Two text boxes with labels above each one. The user can type freely into each box.
Key attributes often used with type="text":
| Attribute | What it does | Example |
|---|---|---|
value |
Pre-fills the field with a default value | value="John" |
placeholder |
Shows greyed-out hint text inside the field | placeholder="Enter your name" |
maxlength |
Limits how many characters the user can type | maxlength="50" |
size |
Sets the visible width of the input (in characters) | size="30" |
readonly |
User can see but not edit the value | readonly |
disabled |
Field is greyed out and unusable | disabled |
required |
Form cannot be submitted if this field is empty | required |
Example with common attributes:
<label for="city">City:</label>
<input type="text" id="city" name="city"
placeholder="Enter your city"
maxlength="100"
required>
Expected Output: A text box with greyed-out hint text “Enter your city”. If the user tries to submit the form without filling this field, the browser shows an error.
type="password" — Password Input
Creates a text box where typed characters are hidden (shown as dots or asterisks).
<form>
<label for="pwd">Password:</label><br>
<input type="password" id="pwd" name="password">
</form>
Expected Output: A text box where everything the user types appears as ●●●●● (dots). This protects passwords from being seen by onlookers.
Security Note:
type="password"only hides characters visually. To truly protect passwords, you must usemethod="post"on the form AND use HTTPS on your server. Never usemethod="get"with passwords.
type="submit" — The Submit Button
Creates a button that submits the form.
<form action="/process.php" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name"><br><br>
<input type="submit" value="Register Now">
</form>
Expected Output: A clickable button with the text “Register Now”. Clicking it sends the form data to /process.php.
- The
valueattribute sets the text on the button. - If you leave out
value, the button shows the default text “Submit”.
type="reset" — The Reset Button
Creates a button that clears all fields in the form back to their default values.
<input type="reset" value="Clear Form">
Expected Output: A button labelled “Clear Form”. Clicking it erases everything the user has typed.
Tip: Use reset buttons carefully — users accidentally click them and lose all their work. Many modern forms leave out the reset button for this reason.
type="button" — A General-Purpose Button
Creates a clickable button that does nothing by default. You need JavaScript to make it do something. (We will not use JavaScript here, but knowing it exists is important.)
<input type="button" value="Click Me">
Expected Output: A button labelled “Click Me” that appears but does nothing unless JavaScript handles the click.
type="checkbox" — Tick Boxes
Creates a small square box the user can tick or untick. Used when the user can select multiple options at once.
<form>
<p>Select your interests:</p>
<input type="checkbox" id="coding" name="interest" value="coding">
<label for="coding">Coding</label><br>
<input type="checkbox" id="music" name="interest" value="music">
<label for="music">Music</label><br>
<input type="checkbox" id="sports" name="interest" value="sports">
<label for="sports">Sports</label><br>
<input type="submit" value="Submit">
</form>
Expected Output: Three tick-box options (Coding, Music, Sports). The user can tick any combination — none, some, or all.
Key attribute:
checked— Pre-selects the checkbox when the page loads:
<input type="checkbox" id="newsletter" name="newsletter" value="yes" checked>
<label for="newsletter">Subscribe to newsletter</label>
Thinking Prompt: What is the difference between type="checkbox" and type="radio"? With checkboxes, users can pick multiple options. With radio buttons (coming next), users can only pick one.
type="radio" — Radio Buttons
Creates circular buttons where the user can only select one option from a group. All radio buttons in the same group must share the same name attribute.
<form>
<p>What is your gender?</p>
<input type="radio" id="male" name="gender" value="male">
<label for="male">Male</label><br>
<input type="radio" id="female" name="gender" value="female">
<label for="female">Female</label><br>
<input type="radio" id="other" name="gender" value="other">
<label for="other">Prefer not to say</label>
</form>
Expected Output: Three circular radio buttons. Selecting one automatically deselects any other. The user can only have one selected at a time.
Why same name? The browser groups radio buttons by their name attribute. All radio buttons with name="gender" form one group. Only one can be selected within a group.
Pre-select one with checked:
<input type="radio" id="male" name="gender" value="male" checked>
type="email" — Email Address Field
Creates a text box specifically for email addresses. The browser validates that the input contains an @ symbol before allowing the form to submit.
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" placeholder="you@example.com" required>
Expected Output: A text box. If the user types “hello” (no @) and clicks Submit, the browser shows: “Please include an ‘@’ in the email address.”
On mobile devices, type="email" also shows a keyboard that includes @ and .com for easier typing.
type="number" — Number Input
Creates a number field with up/down arrow buttons (spinner). Only numbers can be entered.
<label for="age">Your Age:</label>
<input type="number" id="age" name="age" min="1" max="120" value="18">
Expected Output: A field containing “18” with small up/down arrows. Users can only type numbers. The min and max attributes limit the range.
| Attribute | Meaning | Example |
|---|---|---|
min |
Minimum allowed value | min="0" |
max |
Maximum allowed value | max="100" |
step |
How much the value jumps when using the arrows | step="5" means jumps by 5 |
value |
Default value shown on load | value="18" |
type="range" — Slider
Creates a sliding scale control. Good for ratings, volume, or any value within a range.
<label for="rating">Rate our service (1-10):</label>
<input type="range" id="rating" name="rating" min="1" max="10" value="5">
Expected Output: A horizontal slider bar. The user drags it left or right to pick a value between 1 and 10. The slider starts in the middle (value 5).
type="date" — Date Picker
Creates a date picker. The browser shows a calendar popup for selecting a date.
<label for="birthday">Date of Birth:</label>
<input type="date" id="birthday" name="birthday">
Expected Output: A field that opens a calendar when clicked. The user selects a day, month, and year. The date is stored in YYYY-MM-DD format.
<!-- With min and max dates -->
<input type="date" id="appt" name="appointment" min="2024-01-01" max="2025-12-31">
type="time" — Time Picker
Creates a field for entering a time (hours and minutes).
<label for="appttime">Appointment Time:</label>
<input type="time" id="appttime" name="appttime">
Expected Output: A field showing HH:MM with up/down controls for hours and minutes.
type="color" — Colour Picker
Creates a colour picker control. The user clicks to open a colour selection panel.
<label for="favcolor">Choose your favourite colour:</label>
<input type="color" id="favcolor" name="favcolor" value="#ff0000">
Expected Output: A small coloured square (default red). Clicking it opens a full colour picker panel. The value is always a hex colour code like #ff0000.
type="url" — URL / Website Address Field
Creates a field for entering a URL. The browser validates that it starts with http:// or https://.
<label for="website">Your Website:</label>
<input type="url" id="website" name="website" placeholder="https://example.com">
Expected Output: A text field. If the user enters “google” (without https://) and submits, the browser shows an error asking for a valid URL.
type="tel" — Telephone Number Field
Creates a field for phone numbers. Unlike type="number", it allows dashes, spaces, and brackets — all common in phone numbers.
<label for="phone">Phone Number:</label>
<input type="tel" id="phone" name="phone" placeholder="+234 800 000 0000">
Expected Output: A text box optimised for phone numbers. On mobile devices, it shows the numeric keyboard automatically.
type="search" — Search Field
Creates a field specifically for search inputs. In some browsers it shows a small ‘X’ to clear the field.
<label for="search">Search:</label>
<input type="search" id="search" name="search" placeholder="Search the site...">
type="file" — File Upload Field
Creates a field that lets the user upload a file from their computer.
<label for="cv">Upload Your CV:</label>
<input type="file" id="cv" name="cv">
Expected Output: A “Choose File” button. Clicking it opens the computer’s file browser. The user selects a file.
Important: When using type="file", the <form> must also have enctype="multipart/form-data":
<form action="/upload.php" method="post" enctype="multipart/form-data">
<label for="photo">Upload Profile Photo:</label>
<input type="file" id="photo" name="photo" accept="image/*">
<input type="submit" value="Upload">
</form>
enctype="multipart/form-data"— Required for file uploads. Without it, only the file name (not the actual file) gets sent.accept="image/*"— Filters the file browser to show only image files.
type="hidden" — Hidden Field
Creates an invisible field. The user cannot see or change it, but the value is sent to the server when the form is submitted. Used to pass background data.
<input type="hidden" name="user_id" value="12345">
Expected Output: Nothing visible on the page. But when the form is submitted, user_id=12345 is sent along with the other form data.
Real-world use: Hidden fields are used to pass a session token, a product ID, or a page reference that the user should not be able to change but that the server needs to process the form correctly.
type="image" — Image Submit Button
Creates an image that acts as a submit button.
<input type="image" src="submit-btn.png" alt="Submit" width="100" height="40">
Expected Output: Your image appears. Clicking it submits the form.
Summary Table of All Input Types
| Type | What it creates |
|---|---|
text |
Single-line text box |
password |
Text box where characters are hidden |
email |
Text box with email format validation |
number |
Number field with spinner arrows |
range |
Sliding scale |
date |
Date picker (calendar popup) |
time |
Time input |
color |
Colour picker |
url |
URL/website address field |
tel |
Telephone number field |
search |
Search box |
checkbox |
Tick box (multiple can be selected) |
radio |
Circle button (only one per group can be selected) |
file |
File upload button |
submit |
Button that submits the form |
reset |
Button that clears the form |
button |
Generic clickable button |
hidden |
Invisible field (not seen by user) |
image |
Image that acts as a submit button |
Part 5: Other Important Form Elements
Beyond <input>, there are several other elements that create form controls.
<textarea> — Multi-line Text Box
<input type="text"> creates a single line. But what if you want the user to write a full paragraph? Use <textarea>.
<label for="message">Your Message:</label><br>
<textarea id="message" name="message" rows="5" cols="40" placeholder="Type your message here..."></textarea>
Expected Output: A resizable multi-line text box, 5 rows tall and 40 columns wide. The user can type as much as they want, with line breaks.
Key attributes:
| Attribute | What it does |
|---|---|
rows |
Number of visible lines (height) |
cols |
Number of visible characters per line (width) |
placeholder |
Hint text inside the box |
maxlength |
Maximum number of characters allowed |
readonly |
User can read but not edit |
required |
Must not be empty before submitting |
Note: Unlike
<input>,<textarea>has a closing tag</textarea>. The default text content goes between the tags:<textarea>This is default text inside the textarea</textarea>
<select> — Drop-Down List
Creates a drop-down menu. The user clicks to open it and selects one option.
<label for="country">Country:</label>
<select id="country" name="country">
<option value="ng">Nigeria</option>
<option value="gh">Ghana</option>
<option value="ke">Kenya</option>
<option value="za">South Africa</option>
</select>
Expected Output: A drop-down showing “Nigeria” (first option) by default. Clicking opens the list with all four countries. Selecting one closes the list.
Key attributes on <select>:
| Attribute | What it does |
|---|---|
name |
The name sent to the server |
size |
Shows multiple options as a list (not drop-down) |
multiple |
Allows selecting multiple options |
required |
Must have a selection before submitting |
Making a pre-selected option:
<option value="ng" selected>Nigeria</option>
The selected attribute on an <option> makes it the default choice.
Showing multiple visible options (not a dropdown):
<select name="languages" size="4" multiple>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
<option value="python">Python</option>
</select>
Expected Output: A list box showing all 4 options at once. Holding Ctrl (Windows) or Cmd (Mac) lets the user select multiple items.
<option> and <optgroup> — Options and Groups
<option> defines each item inside a <select>. <optgroup> groups related options with a label.
<select name="car">
<optgroup label="African Cars">
<option value="innoson">Innoson IVM</option>
<option value="kiira">Kiira EV</option>
</optgroup>
<optgroup label="Japanese Cars">
<option value="toyota">Toyota</option>
<option value="honda">Honda</option>
</optgroup>
</select>
Expected Output: A drop-down with options grouped under bolded, non-selectable headers “African Cars” and “Japanese Cars”.
<datalist> — Autocomplete Suggestions
<datalist> creates a list of suggested values for an <input> field. It is like a drop-down that also allows free typing.
<label for="browser">Favourite Browser:</label>
<input list="browsers" id="browser" name="browser" placeholder="Type or choose...">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
<option value="Opera">
</datalist>
Expected Output: A text field. When the user starts typing, a dropdown of matching suggestions appears. The user can also type something not in the list.
Key connection: The list attribute on <input> must match the id on <datalist>.
Difference between <select> and <datalist>:
<select>forces the user to pick only from the given options.<datalist>suggests options but allows the user to type anything.
<button> Element
The <button> element creates a clickable button. Unlike <input type="button">, the <button> element can contain HTML content (text, icons, images).
<!-- A submit button using <button> -->
<button type="submit">Submit Form</button>
<!-- A reset button -->
<button type="reset">Clear</button>
<!-- A button with an icon (text emoji here) -->
<button type="submit">🚀 Launch</button>
Expected Output: A clickable button. The type attribute determines what it does:
type="submit"— Submits the form (default iftypeis omitted inside a form).type="reset"— Resets all form fields.type="button"— Does nothing (for JavaScript).
Always specify
typeon<button>inside a form. If you forget, the default istype="submit", which might submit your form when you did not intend to.
<fieldset> and <legend> — Grouping and Labelling Sections
<fieldset> groups related inputs together, drawing a visible box around them. <legend> gives the group a title that appears at the top of the box.
<form action="/register.php" method="post">
<fieldset>
<legend>Personal Information</legend>
<label for="fname">First Name:</label>
<input type="text" id="fname" name="firstname"><br><br>
<label for="email">Email:</label>
<input type="email" id="email" name="email">
</fieldset>
<fieldset>
<legend>Account Details</legend>
<label for="username">Username:</label>
<input type="text" id="username" name="username"><br><br>
<label for="pwd">Password:</label>
<input type="password" id="pwd" name="password">
</fieldset>
<button type="submit">Create Account</button>
</form>
Expected Output: Two visually separated sections, each inside a labelled box. “Personal Information” section contains name and email. “Account Details” section contains username and password.
Why use <fieldset> and <legend>?
- Makes long forms easier to navigate.
- Helps screen readers understand the form’s structure.
- Groups logically related fields visually.
<output> — Displaying Calculation Results
<output> displays the result of a calculation or user action. It updates dynamically with JavaScript.
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
<input type="number" id="a" name="a" value="0"> +
<input type="number" id="b" name="b" value="0"> =
<output name="result" for="a b">0</output>
</form>
Expected Output: Two number fields and a result that updates live as you type. If you type 5 and 3, the output shows 8 immediately.
Part 6: Important Input Attributes (The Full Set)
Input attributes give you precise control over how each field behaves. Here is a comprehensive reference.
name — The Key Sent to the Server
Every input that needs to send data to the server must have a name attribute. Without name, the field’s value will not be sent.
<!-- This value WILL be sent: name="username" -->
<input type="text" name="username" value="Chidi">
<!-- This value will NOT be sent: no name attribute -->
<input type="text" value="Chidi">
When submitted, the server receives: username=Chidi
value — Pre-filled Default Value
The value attribute sets what the field shows when the page first loads.
<input type="text" name="country" value="Nigeria">
Expected Output: The text box already contains “Nigeria”. The user can change it.
For checkboxes and radio buttons, value is the data sent to the server when the option is selected:
<input type="checkbox" name="agree" value="yes"> I agree to the terms
If checked: sends agree=yes. If unchecked: sends nothing.
placeholder — Hint Text Inside the Field
Shows light greyed-out text inside an empty field as a hint to the user. It disappears as soon as the user starts typing.
<input type="email" name="email" placeholder="your.email@example.com">
Expected Output: The field shows your.email@example.com in grey. When the user clicks and types, the hint disappears.
Do not use
placeholderas a replacement for<label>. Placeholder text disappears when the user starts typing, leaving them with no reminder of what the field is for. Always use a visible<label>alongside your placeholder.
required — Must Be Filled
When required is present, the browser will not allow the form to be submitted until this field has a value.
<input type="text" name="name" required>
<input type="email" name="email" required>
Expected Output: If the user clicks Submit without filling in these fields, the browser highlights them and shows a message like “Please fill in this field.”
readonly — Can See But Cannot Edit
The user can read the value but cannot change it.
<input type="text" name="userid" value="USER-00123" readonly>
Expected Output: A field showing “USER-00123” that the user cannot type into. The value IS still sent to the server when the form is submitted.
disabled — Greyed Out and Unusable
The field is visible but completely non-interactive. The user cannot click, type, or select it. Unlike readonly, disabled fields are NOT sent to the server.
<input type="text" name="offer_code" value="SUMMER2024" disabled>
Expected Output: A greyed-out field showing “SUMMER2024”. The user cannot change it, and this value is NOT included when the form is submitted.
Key difference between
readonlyanddisabled:
readonly— User cannot edit, but value IS sent to server.disabled— User cannot interact, and value is NOT sent to server.
maxlength and minlength — Character Limits
<!-- No more than 50 characters -->
<input type="text" name="title" maxlength="50">
<!-- Must have at least 8 characters -->
<input type="password" name="pwd" minlength="8" required>
maxlength silently stops the user from typing more than the limit. minlength triggers a browser error at submit time if the input is too short.
min and max — Number/Date Range Limits
Used with type="number", type="date", type="range", type="time".
<input type="number" name="quantity" min="1" max="99">
<input type="date" name="checkIn" min="2025-01-01">
step — Jump Interval for Numbers and Ranges
Defines the legal interval between values.
<!-- Only allows 0, 5, 10, 15, 20... -->
<input type="number" name="score" min="0" max="100" step="5">
<!-- Only allows even numbers -->
<input type="number" name="even" min="0" step="2">
autofocus — Automatically Focus This Field
Moves the cursor into this field immediately when the page loads.
<input type="text" name="search" autofocus placeholder="Start searching...">
Expected Output: When the page opens, the cursor is already inside the search box — the user can start typing immediately without clicking.
Only one field per page should have
autofocus.
autocomplete — Browser Auto-fill Control
Controls whether the browser offers to auto-complete this specific field (independent of the <form> level autocomplete).
<!-- Allow browser to suggest saved addresses -->
<input type="text" name="address" autocomplete="on">
<!-- Do NOT suggest anything for this field -->
<input type="password" name="newpassword" autocomplete="new-password">
multiple — Allow Multiple Values
For type="email" and type="file", allows entering multiple values separated by commas.
<!-- User can type multiple emails separated by commas -->
<input type="email" name="recipients" multiple>
<!-- User can select multiple files at once -->
<input type="file" name="photos" multiple accept="image/*">
pattern — Custom Validation with Regular Expressions
Specifies a pattern (regular expression) that the field’s value must match.
<!-- Must be exactly 11 digits (like a Nigerian phone number) -->
<input type="tel" name="phone" pattern="[0-9]{11}"
title="Please enter an 11-digit phone number">
<!-- Must be 6 uppercase letters or digits (like a postcode) -->
<input type="text" name="postcode" pattern="[A-Z0-9]{6}"
title="Please enter a 6-character postcode (uppercase letters and numbers)">
patterntakes a regular expression (a pattern-matching formula).titleprovides the error message hint shown to the user.- If the input does not match the pattern, the form cannot be submitted.
list — Connect Input to a <datalist>
Links an <input> to a <datalist> for autocomplete suggestions.
<input type="text" name="city" list="nigerian-cities" placeholder="Choose a city">
<datalist id="nigerian-cities">
<option value="Lagos">
<option value="Abuja">
<option value="Kano">
<option value="Port Harcourt">
<option value="Ibadan">
</datalist>
size — Visible Width of the Input Box
Sets how wide the input box appears (measured in number of characters visible at once).
<input type="text" name="shortcode" size="5"> <!-- Very narrow box -->
<input type="text" name="fullname" size="40"> <!-- Wide box -->
sizeonly affects the visual width. It does not limit how much text the user can type (usemaxlengthfor that).
Part 7: Form Attributes That Work on Input Elements
Some attributes can be added directly to <input> or <button> elements to override the <form>-level settings for that specific element. These are called form override attributes.
formaction — Override the Form’s action
Allows a specific submit button to send the form to a different URL than the form’s action.
<form action="/save-draft.php" method="post">
<input type="text" name="title" placeholder="Post title">
<textarea name="content" placeholder="Write your post..."></textarea>
<!-- This button uses the form's action (/save-draft.php) -->
<button type="submit">Save Draft</button>
<!-- This button overrides and sends to /publish.php instead -->
<button type="submit" formaction="/publish.php">Publish Now</button>
</form>
Expected Output: Two submit buttons. “Save Draft” sends to /save-draft.php. “Publish Now” sends to /publish.php. Both buttons submit the same form data.
Real-world use: A blog editor form with both a “Save Draft” button and a “Publish” button — same form, different destinations.
formmethod — Override the Form’s method
Allows a specific button to use a different HTTP method (GET or POST) than the rest of the form.
<form action="/search.php" method="post">
<input type="text" name="query">
<!-- Normal submit: POST to /search.php -->
<button type="submit">Search</button>
<!-- This button overrides to use GET instead -->
<button type="submit" formmethod="get">Search (Shareable Link)</button>
</form>
formenctype — Override the Form’s enctype
Overrides the encoding type for a specific submit button. Most useful when one button needs to upload a file while another does not.
formtarget — Override the Form’s target
Makes a specific button open the result in a different window/tab.
<form action="/result.php" method="post">
<input type="text" name="data">
<!-- Opens result in same tab (uses form's default) -->
<button type="submit">Submit Here</button>
<!-- Opens result in a new tab -->
<button type="submit" formtarget="_blank">Preview in New Tab</button>
</form>
formnovalidate — Skip Validation for This Button
Lets a specific submit button bypass browser validation.
<form action="/process.php" method="post">
<input type="email" name="email" required>
<!-- Normal submit: validates email format -->
<button type="submit">Submit</button>
<!-- Save without validating: useful for "Save Draft" -->
<button type="submit" formaction="/save-draft.php" formnovalidate>
Save Draft (Skip Validation)
</button>
</form>
Expected Output: Clicking “Submit” validates the email. Clicking “Save Draft” skips validation and saves immediately, even if the email is incomplete.
Guided Practice Exercises
Exercise 1: Build a Basic Login Form
Objective: Create a working login form with all essential fields.
Scenario: You are building the login page for a school management system.
Steps:
- Create
login.html. - Build the complete form:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>School Login</title>
<style>
body { font-family: Arial, sans-serif; max-width: 400px; margin: 50px auto; padding: 20px; }
label { display: block; margin-top: 15px; font-weight: bold; }
input[type="text"], input[type="password"] {
width: 100%; padding: 8px; margin-top: 5px; box-sizing: border-box;
border: 1px solid #ccc; border-radius: 4px;
}
button { margin-top: 20px; padding: 10px 25px; background-color: #2c3e50; color: white;
border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
</style>
</head>
<body>
<h2>Student Login</h2>
<form action="/login.php" method="post" autocomplete="off">
<label for="student_id">Student ID:</label>
<input type="text" id="student_id" name="student_id"
placeholder="e.g. STU-2024-001"
maxlength="15"
required
autofocus>
<label for="password">Password:</label>
<input type="password" id="password" name="password"
placeholder="Enter your password"
minlength="6"
required>
<input type="hidden" name="portal" value="student">
<button type="submit">Log In</button>
</form>
</body>
</html>
Expected Output: A clean login form with a Student ID field (autofocused), a Password field (hidden characters), and a “Log In” button.
Self-check Questions:
- Why did we use
method="post"instead ofmethod="get"? - What does
autocomplete="off"do on this form? - Why is the hidden field
portaluseful here? - What does
minlength="6"do on the password field? - What would happen if we added
autofocusto the password field instead of the student ID field?
Exercise 2: Build a Student Registration Form
Objective: Create a comprehensive multi-section registration form.
Scenario: A university needs a new student registration form.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Student Registration</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 30px auto; padding: 20px; }
fieldset { border: 2px solid #2c3e50; border-radius: 8px; margin-bottom: 20px; padding: 15px; }
legend { font-weight: bold; color: #2c3e50; padding: 0 10px; }
label { display: block; margin-top: 12px; font-weight: bold; }
input[type="text"], input[type="email"], input[type="date"], input[type="tel"],
select, textarea {
width: 100%; padding: 8px; margin-top: 5px; box-sizing: border-box;
border: 1px solid #ccc; border-radius: 4px;
}
.radio-group label, .checkbox-group label { display: inline; font-weight: normal; margin-left: 5px; }
.radio-group, .checkbox-group { margin-top: 8px; }
button { margin-top: 20px; padding: 12px 30px; background-color: #27ae60; color: white;
border: none; border-radius: 4px; cursor: pointer; font-size: 16px; width: 100%; }
</style>
</head>
<body>
<h2>New Student Registration</h2>
<form action="/register.php" method="post">
<!-- SECTION 1: Personal Details -->
<fieldset>
<legend>Personal Information</legend>
<label for="fname">First Name: *</label>
<input type="text" id="fname" name="firstname" placeholder="Your first name" required>
<label for="lname">Last Name: *</label>
<input type="text" id="lname" name="lastname" placeholder="Your last name" required>
<label for="dob">Date of Birth: *</label>
<input type="date" id="dob" name="dob" max="2010-01-01" required>
<label>Gender: *</label>
<div class="radio-group">
<input type="radio" id="male" name="gender" value="male" required>
<label for="male">Male</label>
<input type="radio" id="female" name="gender" value="female">
<label for="female">Female</label>
<input type="radio" id="other_gender" name="gender" value="other">
<label for="other_gender">Other</label>
</div>
</fieldset>
<!-- SECTION 2: Contact Details -->
<fieldset>
<legend>Contact Information</legend>
<label for="email">Email Address: *</label>
<input type="email" id="email" name="email" placeholder="student@university.edu" required>
<label for="phone">Phone Number: *</label>
<input type="tel" id="phone" name="phone"
placeholder="08012345678"
pattern="[0-9]{11}"
title="Please enter an 11-digit phone number"
required>
<label for="state">State of Origin: *</label>
<select id="state" name="state" required>
<option value="">-- Select State --</option>
<option value="abia">Abia</option>
<option value="abuja">Abuja (FCT)</option>
<option value="anambra">Anambra</option>
<option value="lagos" selected>Lagos</option>
<option value="kano">Kano</option>
<option value="rivers">Rivers</option>
</select>
</fieldset>
<!-- SECTION 3: Academic Details -->
<fieldset>
<legend>Academic Information</legend>
<label for="faculty">Faculty: *</label>
<select id="faculty" name="faculty" required>
<optgroup label="Science & Technology">
<option value="cs">Computer Science</option>
<option value="eng">Engineering</option>
<option value="math">Mathematics</option>
</optgroup>
<optgroup label="Arts & Social Sciences">
<option value="econ">Economics</option>
<option value="law">Law</option>
<option value="polsci">Political Science</option>
</optgroup>
</select>
<label for="about">Tell us about yourself:</label>
<textarea id="about" name="about" rows="4"
placeholder="Write a short paragraph about yourself, your goals, and why you chose this university..."
maxlength="500"></textarea>
<label>Preferred Study Mode: *</label>
<div class="radio-group">
<input type="radio" id="full_time" name="study_mode" value="fulltime" checked required>
<label for="full_time">Full-time</label>
<input type="radio" id="part_time" name="study_mode" value="parttime">
<label for="part_time">Part-time</label>
</div>
<label>Subjects of Interest:</label>
<div class="checkbox-group">
<input type="checkbox" id="prog" name="interest" value="programming">
<label for="prog">Programming</label><br>
<input type="checkbox" id="data" name="interest" value="data_science">
<label for="data">Data Science</label><br>
<input type="checkbox" id="design" name="interest" value="design">
<label for="design">Web Design</label><br>
<input type="checkbox" id="ai" name="interest" value="ai">
<label for="ai">Artificial Intelligence</label>
</div>
</fieldset>
<!-- SECTION 4: Documents -->
<fieldset>
<legend>Upload Documents</legend>
<label for="photo">Passport Photo:</label>
<input type="file" id="photo" name="passport_photo" accept="image/*">
<label for="cert">O'Level Certificate (PDF):</label>
<input type="file" id="cert" name="olevel_cert" accept=".pdf">
</fieldset>
<!-- Terms and Submit -->
<div class="checkbox-group">
<input type="checkbox" id="terms" name="agree_terms" value="yes" required>
<label for="terms"> I agree to the <a href="/terms.html">Terms and Conditions</a></label>
</div>
<button type="submit">Submit Registration</button>
</form>
</body>
</html>
Expected Output: A fully styled, multi-section registration form with four fieldset groups covering personal information, contact details, academic choices, and document uploads.
Self-check Questions:
- Why is
enctype="multipart/form-data"missing from this form? What should you add to properly support file uploads? - What does the
max="2010-01-01"on the date field achieve? - Why do all the radio buttons for “gender” share the same
name="gender"? - What happens if a user selects multiple checkboxes for “interest”? How does the server receive that data?
- What is the
optgroupelement doing inside the faculty dropdown?
Hint for file uploads: Add enctype="multipart/form-data" to the <form> opening tag.
Exercise 3: Build a Course Feedback Form with Form-Override Buttons
Objective: Create a form with two different submit buttons that send data to different places.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Course Feedback</title>
<style>
body { font-family: Arial, sans-serif; max-width: 500px; margin: 30px auto; padding: 20px; }
label { display: block; margin-top: 15px; font-weight: bold; }
input[type="text"], select, textarea { width: 100%; padding: 8px; margin-top: 5px; box-sizing: border-box; }
.btn-row { margin-top: 20px; display: flex; gap: 10px; }
button { padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 15px; }
.btn-draft { background-color: #7f8c8d; color: white; }
.btn-submit { background-color: #2c3e50; color: white; }
</style>
</head>
<body>
<h2>Course Feedback Form</h2>
<form action="/submit-feedback.php" method="post">
<label for="course">Course Name:</label>
<select id="course" name="course" required>
<option value="">-- Select Course --</option>
<option value="html_css">HTML & CSS</option>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
</select>
<label for="rating">Overall Rating:</label>
<input type="range" id="rating" name="rating" min="1" max="5" value="3">
<p>Selected: <output for="rating" id="ratingOutput">3</output> / 5</p>
<script>
document.getElementById('rating').addEventListener('input', function() {
document.getElementById('ratingOutput').textContent = this.value;
});
</script>
<label for="comments">Comments:</label>
<textarea id="comments" name="comments" rows="5"
placeholder="Share your experience with this course..."></textarea>
<label for="recommend">Would you recommend this course?</label>
<select id="recommend" name="recommend">
<option value="yes">Yes, definitely!</option>
<option value="maybe">Maybe</option>
<option value="no">No</option>
</select>
<div class="btn-row">
<!-- Save as draft: goes to different URL, skips validation -->
<button type="submit"
class="btn-draft"
formaction="/save-draft.php"
formnovalidate>
Save Draft
</button>
<!-- Full submit: goes to main action URL, validates everything -->
<button type="submit" class="btn-submit">
Submit Feedback
</button>
</div>
</form>
</body>
</html>
Expected Output: A feedback form with a course selector, a live rating slider, a comments textarea, and two buttons. “Save Draft” saves without validation to /save-draft.php. “Submit Feedback” validates and sends to /submit-feedback.php.
Mini Project: Build a Complete Job Application Form
You will now build a real-world job application form that a company could actually use on their website.
Project Overview
A tech company called InnovateTech needs an online job application form. It must collect:
- Applicant’s personal information
- Contact information
- Work experience and skills
- Education
- A cover letter
- A CV file upload
- Agreement to terms
Stage 1: Setup
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>InnovateTech — Job Application</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Segoe UI', Arial, sans-serif;
background-color: #f0f2f5;
color: #2c3e50;
padding: 30px 20px;
}
.page-header {
background-color: #2c3e50;
color: white;
padding: 25px 30px;
border-radius: 8px 8px 0 0;
max-width: 700px;
margin: 0 auto;
}
.page-header h1 { font-size: 24px; }
.page-header p { margin-top: 5px; opacity: 0.8; }
form {
background-color: white;
max-width: 700px;
margin: 0 auto;
padding: 30px;
border-radius: 0 0 8px 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
fieldset {
border: 2px solid #ecf0f1;
border-radius: 6px;
padding: 20px;
margin-bottom: 25px;
}
legend {
background-color: #2c3e50;
color: white;
padding: 5px 15px;
border-radius: 4px;
font-weight: bold;
}
label {
display: block;
margin-top: 15px;
font-weight: bold;
font-size: 14px;
}
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="date"],
select,
textarea {
width: 100%;
padding: 10px 12px;
margin-top: 6px;
border: 1px solid #bdc3c7;
border-radius: 4px;
font-size: 15px;
}
input[type="file"] { margin-top: 8px; }
.radio-inline input, .checkbox-inline input { width: auto; margin-right: 6px; }
.radio-inline label, .checkbox-inline label { display: inline; font-weight: normal; }
.option-group { margin-top: 10px; line-height: 2; }
.btn-row { margin-top: 25px; display: flex; gap: 15px; flex-wrap: wrap; }
button {
padding: 12px 28px;
font-size: 16px;
border: none;
border-radius: 5px;
cursor: pointer;
}
.btn-draft { background-color: #95a5a6; color: white; }
.btn-submit { background-color: #27ae60; color: white; flex: 1; }
.required-note { font-size: 13px; color: #7f8c8d; margin-bottom: 15px; }
.char-count { font-size: 12px; color: #7f8c8d; text-align: right; margin-top: 3px; }
</style>
</head>
<body>
<div class="page-header">
<h1>InnovateTech — Job Application</h1>
<p>Complete all sections. Fields marked * are required.</p>
</div>
Stage 2: Personal & Contact Information
Add this inside the <body> after the header div, opening the <form>:
<form action="/apply.php" method="post" enctype="multipart/form-data">
<p class="required-note">* = required field</p>
<!-- ── PERSONAL INFO ── -->
<fieldset>
<legend>👤 Personal Information</legend>
<label for="app_fname">First Name: *</label>
<input type="text" id="app_fname" name="firstname"
placeholder="Your first name" required autofocus>
<label for="app_lname">Last Name: *</label>
<input type="text" id="app_lname" name="lastname"
placeholder="Your last name" required>
<label for="app_dob">Date of Birth: *</label>
<input type="date" id="app_dob" name="dob"
max="2005-12-31" required>
<label>Gender:</label>
<div class="option-group">
<span class="radio-inline">
<input type="radio" id="g_male" name="gender" value="male">
<label for="g_male">Male</label>
</span>
<span class="radio-inline">
<input type="radio" id="g_female" name="gender" value="female">
<label for="g_female">Female</label>
</span>
<span class="radio-inline">
<input type="radio" id="g_other" name="gender" value="other">
<label for="g_other">Prefer not to say</label>
</span>
</div>
</fieldset>
<!-- ── CONTACT INFO ── -->
<fieldset>
<legend>📞 Contact Information</legend>
<label for="app_email">Email Address: *</label>
<input type="email" id="app_email" name="email"
placeholder="you@example.com" required>
<label for="app_phone">Phone Number: *</label>
<input type="tel" id="app_phone" name="phone"
placeholder="08012345678"
pattern="[0-9]{11}"
title="Enter an 11-digit phone number"
required>
<label for="app_linkedin">LinkedIn Profile URL:</label>
<input type="url" id="app_linkedin" name="linkedin"
placeholder="https://linkedin.com/in/yourname">
<label for="app_city">City: *</label>
<input type="text" id="app_city" name="city"
list="nigerian-cities" required>
<datalist id="nigerian-cities">
<option value="Lagos">
<option value="Abuja">
<option value="Port Harcourt">
<option value="Kano">
<option value="Ibadan">
<option value="Enugu">
<option value="Benin City">
</datalist>
</fieldset>
Stage 3: Role, Skills & Experience
<!-- ── ROLE & SKILLS ── -->
<fieldset>
<legend>💼 Role & Skills</legend>
<label for="app_role">Position Applying For: *</label>
<select id="app_role" name="role" required>
<option value="">-- Select a Position --</option>
<optgroup label="Engineering">
<option value="frontend">Frontend Developer</option>
<option value="backend">Backend Developer</option>
<option value="fullstack">Full-Stack Developer</option>
</optgroup>
<optgroup label="Design & Product">
<option value="ux">UX Designer</option>
<option value="pm">Product Manager</option>
</optgroup>
<optgroup label="Data">
<option value="data_analyst">Data Analyst</option>
<option value="ml_engineer">Machine Learning Engineer</option>
</optgroup>
</select>
<label for="app_exp">Years of Experience: *</label>
<input type="number" id="app_exp" name="years_exp"
min="0" max="50" step="1" value="0" required>
<label>Employment Type Preference: *</label>
<div class="option-group">
<span class="radio-inline">
<input type="radio" id="emp_full" name="emp_type" value="fulltime" required checked>
<label for="emp_full">Full-time</label>
</span>
<span class="radio-inline">
<input type="radio" id="emp_part" name="emp_type" value="parttime">
<label for="emp_part">Part-time</label>
</span>
<span class="radio-inline">
<input type="radio" id="emp_remote" name="emp_type" value="remote">
<label for="emp_remote">Remote</label>
</span>
</div>
<label>Core Skills (select all that apply):</label>
<div class="option-group checkbox-inline">
<input type="checkbox" id="sk_html" name="skills" value="HTML_CSS">
<label for="sk_html">HTML/CSS</label><br>
<input type="checkbox" id="sk_js" name="skills" value="JavaScript">
<label for="sk_js">JavaScript</label><br>
<input type="checkbox" id="sk_python" name="skills" value="Python">
<label for="sk_python">Python</label><br>
<input type="checkbox" id="sk_sql" name="skills" value="SQL">
<label for="sk_sql">SQL / Databases</label><br>
<input type="checkbox" id="sk_react" name="skills" value="React">
<label for="sk_react">React / Vue</label><br>
<input type="checkbox" id="sk_cloud" name="skills" value="Cloud">
<label for="sk_cloud">Cloud (AWS / GCP)</label>
</div>
<label for="app_salary">Expected Monthly Salary (₦):</label>
<input type="number" id="app_salary" name="salary_expectation"
min="50000" step="5000" placeholder="e.g. 300000">
<label for="app_start">Earliest Start Date:</label>
<input type="date" id="app_start" name="start_date">
</fieldset>
Stage 4: Cover Letter, CV Upload & Submit
<!-- ── COVER LETTER ── -->
<fieldset>
<legend>📝 Cover Letter</legend>
<label for="app_cover">Write Your Cover Letter: *</label>
<textarea id="app_cover" name="cover_letter" rows="8"
placeholder="Dear Hiring Manager, I am writing to express my interest in..."
maxlength="2000"
required
oninput="document.getElementById('cover_count').textContent = this.value.length"></textarea>
<p class="char-count"><span id="cover_count">0</span> / 2000 characters</p>
</fieldset>
<!-- ── DOCUMENTS ── -->
<fieldset>
<legend>📎 Upload Documents</legend>
<label for="app_cv">Upload Your CV/Resume (PDF only): *</label>
<input type="file" id="app_cv" name="cv_file"
accept=".pdf" required>
<label for="app_portfolio">Upload Portfolio / Work Samples (optional):</label>
<input type="file" id="app_portfolio" name="portfolio"
accept=".pdf,.zip,.docx" multiple>
</fieldset>
<!-- ── AGREEMENT ── -->
<fieldset>
<legend>✅ Declaration</legend>
<div class="checkbox-inline" style="margin-top:10px; line-height:1.8;">
<input type="checkbox" id="accurate" name="accuracy_declaration" value="yes" required>
<label for="accurate">I confirm that all information provided is accurate and truthful.</label><br>
<input type="checkbox" id="terms_agree" name="terms" value="agreed" required>
<label for="terms_agree">I have read and agree to the <a href="/privacy.html">Privacy Policy</a>.</label>
</div>
</fieldset>
<!-- Hidden fields -->
<input type="hidden" name="form_version" value="2025-v1">
<input type="hidden" name="source" value="careers_page">
<!-- Submit Buttons -->
<div class="btn-row">
<button type="submit"
class="btn-draft"
formaction="/save-application-draft.php"
formnovalidate>
💾 Save Draft
</button>
<button type="submit" class="btn-submit">
🚀 Submit Application
</button>
</div>
</form>
</body>
</html>
Final Milestone Output:
- A professional-looking two-toned form with a dark header and white form body.
- Five clearly labelled fieldset sections: Personal, Contact, Role & Skills, Cover Letter, Documents.
- Two submit buttons: “Save Draft” (skips validation, goes to draft endpoint) and “Submit Application” (full validation).
- Live character counter on the cover letter textarea.
- City autocomplete with Nigerian cities via
<datalist>. - Proper
enctype="multipart/form-data"for file uploads.
Reflection Questions:
- Why must the
<form>haveenctype="multipart/form-data"for the file uploads to work? - Why did we give the hidden fields
name="form_version"andname="source"? - How does
formnovalidateon the “Save Draft” button help the user experience? - Why did we use
<optgroup>in the role<select>? - What would happen if two different
<select>elements both hadname="role"? Which value would the server receive?
Common Beginner Mistakes
Mistake 1: Forgetting name on Input Fields
What happens: The field value is NOT sent to the server. The server receives nothing from that field.
Wrong:
<input type="text" id="city" placeholder="Enter city">
Correct:
<input type="text" id="city" name="city" placeholder="Enter city">
Mistake 2: Using method="get" for Passwords
What happens: The password appears in the URL like /login?password=abc123 — visible in the browser bar, browser history, server logs, and to anyone watching over the user’s shoulder.
Wrong:
<form action="/login.php" method="get">
<input type="password" name="pwd">
</form>
Correct:
<form action="/login.php" method="post">
<input type="password" name="pwd">
</form>
Mistake 3: Confusing id and name
id connects the label to the input in the HTML page. name is the key sent to the server. They can have the same value (which is common and recommended), but they serve different purposes.
Wrong thinking: “They are the same thing.”
Correct understanding:
<label for="email">Email:</label> <!-- uses id to link -->
<input type="email" id="email" name="email">
<!-- ↑ for label ↑ for server -->
Mistake 4: Radio Buttons With Different name Values
What happens: Each radio button becomes its own independent group. The user can select all of them at once instead of only one.
Wrong:
<input type="radio" id="male" name="gender_male" value="male">
<input type="radio" id="female" name="gender_female" value="female">
Correct: All radio buttons in a group must share exactly the same name:
<input type="radio" id="male" name="gender" value="male">
<input type="radio" id="female" name="gender" value="female">
Mistake 5: Forgetting enctype for File Uploads
What happens: Only the filename is sent to the server. The actual file content is never received. The upload silently fails.
Wrong:
<form action="/upload.php" method="post">
<input type="file" name="cv">
</form>
Correct:
<form action="/upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="cv">
</form>
Mistake 6: Using placeholder Instead of <label>
What happens: When the user clicks the field, the hint text disappears. They forget what they were supposed to type. This is especially frustrating on long forms.
Wrong:
<input type="text" name="fullname" placeholder="Full Name">
Correct:
<label for="fullname">Full Name:</label>
<input type="text" id="fullname" name="fullname" placeholder="e.g. Chidi Okafor">
The placeholder is a supplement to the label, not a replacement.
Mistake 7: A <button> Without type Inside a Form
What happens: All <button> elements default to type="submit" when inside a form. A button intended as a general-purpose button (e.g., “Show Password”) accidentally submits the form.
Wrong:
<button onclick="showPreview()">Preview</button> <!-- accidentally submits form! -->
<button type="submit">Submit</button>
Correct:
<button type="button" onclick="showPreview()">Preview</button> <!-- safe -->
<button type="submit">Submit</button>
Mistake 8: Forgetting for/id Connection on Labels
What happens: Clicking the label text does NOT focus the input. Accessibility for screen readers is broken.
Wrong:
<label>Username:</label>
<input type="text" name="username">
Correct:
<label for="username">Username:</label>
<input type="text" id="username" name="username">
Reflection Questions
- In your own words, explain what an HTML form does and why every useful website needs one.
- What is the difference between
method="get"andmethod="post"? Give a real example of when you would use each. - What does the
actionattribute on a<form>do? - Name five different values for
typeon the<input>element and explain what each one creates. - Why must radio buttons in the same group share the same
nameattribute? - What is the difference between
<select>(a dropdown) and<datalist>(autocomplete suggestions)? - When would you use
<fieldset>and<legend>? Why? - What is the difference between
required,readonly, anddisabled? - What does
enctype="multipart/form-data"do, and when is it required? - What is
formactionand why is it useful to have two submit buttons with differentformactionvalues? - What is a hidden input field used for? Give a real-world example.
- Explain the difference between the
valueattribute and theplaceholderattribute on an<input>. - What does
autofocusdo, and why should only one field per page use it? - What is the
patternattribute and what kind of value does it take? - In what situation would you use
type="image"instead oftype="submit"?
Completion Checklist
- I understand what an HTML form is and why it is used.
- I can write a
<form>element with the correctaction,method, andenctypeattributes. - I know the difference between
method="get"andmethod="post". - I can create text, password, email, number, date, and range input fields.
- I understand how checkboxes and radio buttons differ in usage.
- I know how to create a dropdown list with
<select>and<option>. - I know how to group dropdown options with
<optgroup>. - I can create an autocomplete field using
<datalist>. - I can build a multi-line text area with
<textarea>. - I can upload files using
type="file"with the correctenctype. - I know when and how to use
<fieldset>and<legend>. - I understand the difference between
readonlyanddisabled. - I can use
required,maxlength,minlength,min,max,step, andpattern. - I know what
autofocus,placeholder,value, andnamedo. - I understand hidden input fields and what they are used for.
- I can use
formaction,formmethod,formtarget, andformnovalidateon submit buttons. - I have completed all three guided exercises.
- I have built the complete job application mini-project.
- I can list at least five common beginner mistakes in form building.
Lesson Summary
In this lesson, you have mastered the complete set of HTML form tools. Here is a quick reference:
The Form Container:
<form action="/url" method="post" enctype="multipart/form-data"
autocomplete="off" novalidate target="_blank">
The Most Common Input Types:
<input type="text"> <!-- Single-line text -->
<input type="password"> <!-- Hidden text -->
<input type="email"> <!-- Email with @ validation -->
<input type="number"> <!-- Numbers with min/max/step -->
<input type="date"> <!-- Calendar date picker -->
<input type="checkbox"> <!-- Tick-box (multiple allowed) -->
<input type="radio"> <!-- Circle button (one per group) -->
<input type="file"> <!-- File upload -->
<input type="submit"> <!-- Submit the form -->
<input type="hidden"> <!-- Invisible data field -->
Other Key Elements:
<textarea rows="5" cols="40"></textarea> <!-- Multi-line text -->
<select><option>...</option></select> <!-- Drop-down list -->
<datalist><option>...</option></datalist> <!-- Autocomplete -->
<fieldset><legend>...</legend></fieldset> <!-- Section grouper -->
<button type="submit|reset|button"> <!-- Flexible button -->
<label for="id">Text</label> <!-- Field label -->
Critical Input Attributes:
name → The key sent to the server (required for all submittable fields)
value → Pre-filled default value
placeholder → Hint text inside empty field
required → Must be filled before submitting
readonly → Visible but not editable (still sent to server)
disabled → Greyed out and not sent to server
maxlength → Maximum characters allowed
pattern → Custom regex validation rule
autofocus → Move cursor here on page load
Form-Override Button Attributes:
formaction → Send this button's data to a different URL
formmethod → Override the form's GET/POST method
formtarget → Open response in different window/tab
formnovalidate → Skip browser validation for this button only
HTML forms are the bridge between your users and your application’s data. With what you have learned in this lesson, you can build forms for any real-world use case — from simple contact pages to complex multi-step applications.