Inputs, Labels, and Why <label> Matters
Start the signup form: name, email, password, and a checkbox agreeing to terms. The markup looks trivial, but each piece carries weight most people skip past.
Input types are not interchangeable
Every <input> has a type, and the type changes more than validation - it changes the keyboard a
phone shows, the browser's built-in checks, and how the value gets stored.
text- a plain string. No format checking, no special keyboard.email- mobile browsers show an@key; desktop browsers reject submission if the value has no@and domain shape, even before you write a line of JavaScript.password- masks the characters as dots and tells password managers this field is sensitive.checkbox- a boolean. Checked or not; there's no "value" the user types.
There's also radio for picking one option from a set:
Free
Pro
Radio buttons only work as a group when they share the same name - that's how the browser knows
they're mutually exclusive. Give each one a different value so you know which was picked.
📝 Terminology. type="email" doesn't guarantee a real, deliverable email address - it only
checks the address is shaped like one ([email protected]). Confirming the address exists
still needs a verification email.
<label> is not decoration
A <label> wrapped around text next to an input looks the same with or without the for attribute.
The difference only shows up when someone interacts with the page differently than you did while
building it.
Email
The for attribute must match the input's id. That connection does two concrete things:
- Bigger click target. Clicking the label text "Email" focuses the input - not just clicking the box itself. For checkboxes and radio buttons this matters even more: the label turns a tiny 16px square into a click target the width of the whole sentence.
- Screen reader association. Without
for/id, a screen reader announces "edit text, blank." With it, the reader announces "Email, edit text, blank" - the user knows what they're filling in before they start typing. This is table stakes, not a nice-to-have; the full accessibility treatment for forms and beyond is in Accessibility From Day One.
⚠️ Gotcha. A placeholder is not a label. Placeholder text disappears the moment someone starts
typing, has no association a screen reader relies on, and often fails color-contrast checks because
it's styled light gray by default. Use placeholder for a format hint ("MM/DD/YYYY") alongside a real
<label>, never as a replacement for one.
You can skip for/id by wrapping the input inside the label instead:
Email
This works and is valid HTML, but it's harder to style precisely (the input inherits label layout
quirks) and harder to scan in longer forms. Prefer explicit for/id pairs once a form has more than
one or two fields.
Grouping related inputs with <fieldset>
The "I agree to terms" checkbox is one field, but the moment a form has more than one option that
belongs together - a set of radio buttons, several checkboxes for notification preferences - group them
with <fieldset> and describe the group with <legend>:
Notify me about
Product news
Tips
A screen reader announces the legend before each field inside the fieldset, so "Product news" is heard
as "Notify me about, Product news" - the group's purpose travels with every item in it. Visually,
browsers render a <fieldset> with a border and the <legend> sitting on top of it by default; override
that with CSS if it doesn't fit your design, but keep the elements themselves.
The signup form so far
Full name
Email
Password
Terms
I agree to the terms of service
Create account
Every input has a matching label. The checkbox lives inside its own label so clicking the sentence
toggles it. Next phase turns those stray required attributes into a real validation strategy.
Check what you just covered:
[
{
"q": "What does `<label for=\"email\">` connect to?",
"choices": ["The form's action URL", "An input with a matching id", "The page's title"],
"answer": 1,
"explain": "The for attribute must match the input's id - that pairing is what makes the label clickable and screen-reader-associated."
},
{
"q": "Why shouldn't a placeholder replace a label?",
"choices": ["Placeholders are deprecated", "Placeholder text disappears on typing and isn't reliably read by screen readers", "Placeholders only work on checkboxes"],
"answer": 1,
"explain": "Once the user types, the placeholder is gone - and it was never announced as a real label to begin with."
},
{
"q": "What makes a group of radio buttons mutually exclusive?",
"choices": ["Wrapping them in a <fieldset>", "Giving them the same name attribute", "Giving them the same id"],
"answer": 1,
"explain": "Radio buttons only exclude each other within a shared name group. id must stay unique per element."
}
]
Guide overview · Phase 2: Validation: Built-in vs. Custom →
Check your understanding 3 questions
1. What does `<label for="email">` connect to?
2. Why shouldn't a placeholder replace a label?
3. What makes a group of radio buttons mutually exclusive?