Lesson 8 of 32
Forms and Inputs
form, label, input types, select, textarea and button — how to collect input correctly, associate labels with controls, and avoid the common button-type gotcha.
Forms are how a page collects information from a visitor — a search box, a login, a checkout. This lesson covers the elements involved and a few gotchas that catch people who learn forms informally.
<form> and its two key attributes
<form action="/submit" method="post">
<!-- inputs go here -->
</form>action— the URL the form's data gets sent to when submitted.method— usuallygetorpost.getappends the data to the URL as a query string (fine for something like a search form, since the result can be bookmarked or shared);postsends it in the request body instead, the right choice for anything that changes data or shouldn't be visible in the URL, like a login form.
<label> — the two correct ways to associate it
A label needs to be programmatically tied to its control, not just placed visually near it, or a screen reader has no way to know they belong together. There are two valid ways to do this:
1. Matching for and id:
<label for="email">Email address</label>
<input type="email" id="email" name="email" />2. Wrapping the input inside the label:
<label>
Email address
<input type="email" name="email" />
</label>Both are equally valid and create a real association — clicking the label
text focuses the input either way, and a screen reader announces the label
when the input receives focus. Pick whichever fits your markup better; the
for/id version is more common when the input needs to sit somewhere the
label can't directly wrap.
placeholder is not a label
<!-- Wrong: no real label -->
<input type="email" placeholder="Email address" />
<!-- Right: a real label, placeholder optional on top -->
<label for="email">Email address</label>
<input type="email" id="email" placeholder="you@example.com" />placeholder shows hint text inside an empty field, and it vanishes the
moment the visitor starts typing — at which point, without a real label, the
field's purpose disappears from view entirely. It's also not consistently
announced by assistive technology the same reliable way a proper <label>
is. Use placeholder for a short example of the expected format, on top of a
real label — never as a replacement for one.
<input> and its common types
<input type="text" />
<input type="email" />
<input type="password" />
<input type="number" />
<input type="checkbox" />
<input type="radio" />
<input type="date" />text— plain single-line text, the default iftypeis omitted.email— behaves like text, but mobile browsers show an@-friendly keyboard, and the browser can validate it looks like an email address on submit (more on validation next lesson).password— masks the typed characters.number— restricts input to numeric values and typically shows increment/decrement controls.checkbox— an independent on/off toggle. Multiple checkboxes with the samenamelet a visitor pick any number of options.radio— one choice from a group. Radios sharing the samenameattribute become mutually exclusive — checking one unchecks the others in that group.date— a native date picker.
<label>
<input type="radio" name="plan" value="basic" /> Basic
</label>
<label>
<input type="radio" name="plan" value="pro" /> Pro
</label>Notice both radios share name="plan" — that shared name is what groups
them together as mutually exclusive.
<select> and <option>
<label for="country">Country</label>
<select id="country" name="country">
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
</select><select> renders a dropdown; each <option> is one choice. value is what
gets submitted; the text between the tags is what the visitor sees.
<textarea>
<label for="message">Message</label>
<textarea id="message" name="message" rows="4"></textarea>For multi-line free text. Unlike <input>, its default content goes between
the opening and closing tags, not in a value attribute. rows sets a
starting visible height (the visitor can typically still resize it).
<button> and its types — the real gotcha
<button type="submit">Submit</button>
<button type="button">Cancel</button>
<button type="reset">Reset</button>submit— submits the enclosing form.button— does nothing on its own; used when you're attaching custom JavaScript behaviour instead of a form submission.reset— clears the form back to its default values. Rarely what you actually want on a real form; easy to click by accident and lose everything typed.
The gotcha: a <button> placed inside a <form> with no type
attribute set defaults to type="submit". This surprises people
constantly — add what you thought was a harmless "Cancel" or icon button
inside a form, forget to set type="button", and clicking it submits the
whole form unexpectedly. If a button inside a form isn't meant to submit it,
you must set type="button" explicitly — the browser will not infer that
for you.
Try it yourself
What to remember
- Associate every
<label>with its control via matchingfor/id, or by wrapping the control inside the label. placeholderis a hint on top of a label, never a replacement for one — it disappears once typing starts.- Radios sharing a
namebecome mutually exclusive; checkboxes are independent toggles. - A
<button>inside a<form>defaults totype="submit"— settype="button"explicitly for anything that shouldn't submit.
Check yourself
3 questions · pass 3/3 to unlock Form Validation
1.What are the two valid ways to associate a
<label>with its input?2.A
<button>with notypeattribute, placed inside a<form>, will:3.Why is
placeholdernot a substitute for<label>?
3 left to answer