Forms and Tables
Table of Contents
- What a Form Does
- Labels and Inputs
- Input Types
- Textarea, Select, Checkboxes, and Radios
- Buttons
- Built-in Validation
- Where the Data Goes
- Tables
- Try It Yourself
1. What a Form Does
A form collects input from the user and sends it somewhere. Login boxes, search bars, checkout pages, and comment fields are all forms. HTML gives you every control you need — text boxes, checkboxes, menus, buttons — and the browser provides the behavior: keyboard support, mobile keyboards, and basic validation. All before you write any JavaScript.
The wrapper is the <form> element:
<form action="/contact" method="post">
<!-- controls go here -->
</form>
action is the URL the data is sent to and method is the HTTP method
from HTTP Requests.
Section 7 explains what to do on a static site, where there is no
server to send to.
2. Labels and Inputs
The core pair is a <label> and an <input>:
<label for="name">Your name</label>
<input type="text" id="name" name="name">
Three attributes link everything together:
foron the label matches theidof the input. This connects them: clicking the label focuses the field, and screen readers announce the label when the field is focused.nameis the key under which the value is sent. Without it, the field's value is not sent at all.idmust be unique on the page.
Every form field needs a label. A placeholder is not a label — it
disappears as soon as you type, and it's often too faint to read. You
can use a placeholder as a hint (placeholder="e.g. Dara Sok") in
addition to a label, never instead.
You can also wrap the input inside the label, in which case for and
id aren't needed:
<label>Your name <input type="text" name="name"></label>
3. Input Types
The type attribute turns one element into many controls:
| Type | Gives you | Notes |
|---|---|---|
text | A single-line text box | The default |
email | Text box that checks for an @ | Mobile keyboards show @ |
tel | Phone number | Mobile shows a number pad |
url | A web address | Must start with a scheme |
number | Numeric box with steppers | Supports min, max, step |
password | Dots instead of letters | Hides the text, but is not encrypted by itself |
date | Date picker | Value format is YYYY-MM-DD |
search | A search box | Often has a clear button |
file | File chooser | Needs enctype on the form |
range | A slider | |
color | Color picker | |
hidden | Nothing visible | Sends a fixed value |
Picking the right type is a free upgrade: the right keyboard on phones, automatic validation, and sometimes a native date or color picker.
4. Textarea, Select, Checkboxes, and Radios
<textarea> is for multi-line text. It has a closing tag, and
rows sets its height:
<label for="message">Message</label>
<textarea id="message" name="message" rows="5"></textarea>
<select> is a drop-down menu of <option>s:
<label for="topic">Topic</label>
<select id="topic" name="topic">
<option value="">Choose one…</option>
<option value="job">Job opportunity</option>
<option value="project">Project collaboration</option>
<option value="other">Something else</option>
</select>
Checkboxes are for zero or more choices; radio buttons are for
exactly one. Radios in the same group share the same name. Wrap a group
in a <fieldset> with a <legend> that names it:
<fieldset>
<legend>How should I reply?</legend>
<label><input type="radio" name="reply" value="email" checked> Email</label>
<label><input type="radio" name="reply" value="phone"> Phone</label>
</fieldset>
<label>
<input type="checkbox" name="newsletter" value="yes">
Send me occasional updates
</label>
5. Buttons
The <button> element is a clickable control, and its type matters:
<button type="submit">Send</button>
<button type="reset">Clear</button>
<button type="button">Does nothing by itself</button>
submitsends the form (the default inside a form).resetputs every field back to its starting value.buttondoes nothing until JavaScript is attached to it.
Use <button> for actions and <a> for navigation — a link goes
somewhere, a button does something. Don't make a <div> look like a
button; you'd lose keyboard support and screen-reader meaning.
6. Built-in Validation
Browsers can check input before the form is submitted. Add attributes and the browser stops submission and shows a message when something's wrong:
| Attribute | Effect |
|---|---|
required | Can't be empty |
minlength, maxlength | Limits on text length |
min, max | Limits on numbers and dates |
pattern="[0-9]{9,10}" | Must match a regular expression |
type="email" | Must look like an email address |
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
Try submitting with it empty, then with abc. The browser blocks the
submit and tells you why — no JavaScript involved.
One warning: browser validation is a convenience, not security.
Anyone can bypass it by editing the page in DevTools or sending a
request directly with curl. Any real server must check the data again.
7. Where the Data Goes
When you press Submit, the browser builds an HTTP request out of every
field that has a name. With method="get" the values go into the
query string — ?name=Dara&topic=job, as seen in the URL chapter. With
method="post" they go in the request body. Either way, something
on a server must receive them.
A static site has no server of its own, so it can't process a form by itself. You have three honest options:
mailto:— a plain link that opens the visitor's email app. Simple, and works anywhere, but not a real form.- A form service such as Formspree or Web3Forms. They give you a URL
to use as
action, receive the data, and email it to you. - Your own backend — beyond this series.
For this project, build the form so the HTML is complete and correct,
and point action at a form service later if you want it live. The
markup you write is the same either way.
<form action="https://example.com/your-form-url" method="post">
<h2>Get in touch</h2>
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Send</button>
</form>
8. Tables
A <table> is for tabular data — information that has rows and
columns, like a schedule or a price list. Not for page layout (that's
what chapters 9 and 10 are for).
<table>
<caption>My skills</caption>
<thead>
<tr>
<th scope="col">Skill</th>
<th scope="col">Level</th>
<th scope="col">Since</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTML</td>
<td>Comfortable</td>
<td>2026</td>
</tr>
<tr>
<td>CSS</td>
<td>Learning</td>
<td>2026</td>
</tr>
</tbody>
</table>
The parts:
| Element | Role |
|---|---|
<caption> | Title of the table |
<thead>, <tbody>, <tfoot> | Header, body, and footer row groups |
<tr> | A table row |
<th> | A header cell. scope="col" or scope="row" says which direction it labels |
<td> | A data cell |
Header cells with scope let a screen reader announce "Level:
Comfortable" for a cell, instead of reading a bare "Comfortable" with no
context. To merge cells use colspan and rowspan.
A table with no borders looks like plain text. That's expected — it's CSS's job to make it look good, and you'll do that in chapter 6.
9. Try It Yourself
- Add the contact form. Put the form from section 7 inside the
#contactsection ofindex.html. Check that clicking each label focuses its field. - Test validation. Submit it empty, then with an invalid email.
Add a
minlength="10"on the message and test again. - Try input types. Add
<input type="date">,type="range", andtype="color"to a scratch file. Open the page on your phone via Live Server's network address, or in DevTools device mode, and compare the keyboards fortext,email, andtel. - Bypass your own validation. In DevTools, delete the
requiredattribute from a field and submit it empty. This is why a real server must validate too. - Add a skills table to the About page with a
<caption>, header cells withscope, and at least four rows. - Inspect the traffic. Change the form to
method="get"andaction="https://httpbin.org/get", submit, and read the query string in the address bar.
Commit your work. HTML is now done: you can structure any page. From the next chapter on, we make it look good with CSS.
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!