Form Basics
<form> wrapper that defines where data goes, labels and inputs that collect it, and a submit button that sends it. Master these basics and every form you'll ever build becomes a variation.
The <form> Element
The <form> element is a container. It wraps all the controls that collect data and defines two critical attributes: where the data goes (action) and how it's sent (method).
| Attribute | Values | Effect |
|---|---|---|
action | URL string | Where the form data is sent when submitted. Omit or set to "" for the current page. |
method | get or post | GET appends data to URL (visible, bookmarkable). POST sends data in the body (hidden, for sensitive/large data). |
novalidate | boolean | Disables browser's built-in validation — useful when writing custom JS validation. |
autocomplete | on / off | Controls whether the browser suggests previously entered values. |
enctype | MIME type | Only needed with method="post" and file uploads — set to multipart/form-data. |
<!-- GET: search forms, filters, bookmarkable results --> <form action="/search" method="get"> <!-- inputs go here --> </form> <!-- POST: login, registration, payment, anything sensitive --> <form action="/login" method="post"> <!-- inputs go here --> </form> <!-- File upload needs enctype --> <form action="/upload" method="post" enctype="multipart/form-data"> <!-- file input here --> </form>
Labels & Inputs — The Core Pair
Every input needs a <label>. Labels tell users what to type and are essential for accessibility — screen readers announce the label text when the input is focused. Connect them with matching for and id attributes:
<!-- Method 1: for/id pair (preferred) --> <label for="username">Username</label> <input type="text" id="username" name="username"> <!-- Method 2: wrapping (implicit association) --> <label> Username <input type="text" name="username"> </label>
The name attribute on inputs is what the server sees. It's the key in the key=value pair sent with the form. Without name, the input's value is never submitted.
| Input attribute | Purpose | Example |
|---|---|---|
type | Kind of control rendered | text, email, password |
name | Key sent to server | name="email" |
id | Links to label's for attribute | id="email" |
value | Default/initial value | value="hello@..." |
placeholder | Hint text (fades on type) | placeholder="Enter email" |
required | Must be filled before submit | required |
How Submission Works
name1=value1&name2=value2name keys<form action="/register" method="post"> <label for="name">Full Name</label> <input type="text" id="name" name="name" required> <label for="email">Email Address</label> <input type="email" id="email" name="email" required> <label for="pw">Password</label> <input type="password" id="pw" name="password" minlength="8" required> <button type="submit">Create Account</button> </form>
fieldset and legend
<fieldset> groups related form controls under a <legend> heading. This is especially useful for multi-section forms and improves accessibility by giving groups of radio buttons or checkboxes a clear label.
<form action="/checkout" method="post"> <fieldset> <legend>Personal Information</legend> <label for="first">First Name</label> <input type="text" id="first" name="first"> <label for="last">Last Name</label> <input type="text" id="last" name="last"> </fieldset> <fieldset> <legend>Delivery Address</legend> <label for="city">City</label> <input type="text" id="city" name="city"> </fieldset> <button type="submit">Place Order</button> </form>
Submit vs Button vs Reset
There are three types of buttons inside a form — each has a specific job:
| Button type | Behaviour | When to use |
|---|---|---|
type="submit" | Sends the form data | The main action button — "Sign Up", "Send", "Buy" |
type="button" | Does nothing on its own | Triggering JavaScript actions without submitting |
type="reset" | Clears all inputs to defaults | Rarely used — it annoys users who accidentally click it |
<button> inside a <form> and forget the type attribute, it will submit the form when clicked — including JS buttons you didn't intend to be submit buttons. Always specify type="button" explicitly for non-submit buttons.Create a "Contact Us" page form with:
Fieldset 1 — Your Details:
- First name (text, required)
- Last name (text, required)
- Email (email type, required)
Fieldset 2 — Your Message:
- Subject (text, required)
- Priority (a set of radio buttons: Low / Normal / High)
1. Use
method="post" and action="/contact"2. All inputs must have matching
for/id pairs3. All inputs must have a
name attribute4. Add a
type="submit" button and a type="reset" button5. Style the form so it looks clean — at minimum: labels on their own line, inputs full width, gap between fields
Show hints
- Radio buttons in the same group must share the same
nameattribute - Each radio needs its own unique
idand a matchinglabel for="..." - Add
checkedattribute to the "Normal" radio to pre-select it - For CSS:
label { display: block; margin-bottom: 4px }andinput { width: 100%; padding: 8px; margin-bottom: 16px }