Demo: building a form
A short walkthrough of the controls on this page and how to label them. The video will go here.
Anatomy of a form
A <form> wraps the controls. Three attributes do most of the work:
action (the URL that receives the data), method
(GET for searches, POST for anything private), and every input's
name — without a name, a field is never submitted.
<form action="/submit" method="POST"> ... inputs go here ... <button type="submit">Send</button> </form>
id links an input to its <label> in the browser; name identifies the field in the submitted data. Most inputs want both.Labels: connect every control
A <label> whose for matches the input's id is the single
most important rule in forms. Clicking the label focuses the field, and screen readers announce it.
<label for="city">City</label> <input type="text" id="city" name="city">
<label>.Text, email, password & friends
These specialized text inputs give built-in validation and, on phones, the right on-screen keyboard.
Change the type and the browser does the work.
type="tel" opens the number pad on phones.
<label for="fullname">Full name</label>
<input type="text" id="fullname" name="fullname" placeholder="Ada Lovelace">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<label for="pwd">Password</label>
<input type="password" id="pwd" name="pwd">
<label for="tel">Phone</label>
<input type="tel" id="tel" name="tel" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}">
<label for="url">Website</label>
<input type="url" id="url" name="url" placeholder="https://">
<label for="q">Search</label>
<input type="search" id="q" name="q">
<label for="message">Message</label>
<textarea id="message" name="message"></textarea>
Checkboxes, radios & select
Use a checkbox when options are independent, radio buttons when only
one in a group is allowed (they share a name), and a select for a long
list. Group related controls in a <fieldset> with a <legend>.
<label><input type="checkbox" name="agree" required> I agree to the terms</label> <fieldset> <legend>Contact preference</legend> <label><input type="radio" name="contact" value="email"> Email</label> <label><input type="radio" name="contact" value="phone"> Phone</label> </fieldset> <label for="lang">Favorite language</label> <select id="lang" name="lang"> <option value="">Choose one…</option> <option>HTML</option> <option>CSS</option> <option>JavaScript</option> </select> <label for="browser">Browser (type or pick)</label> <input list="browsers" id="browser" name="browser"> <datalist id="browsers"> <option value="Chrome"> <option value="Firefox"> <option value="Safari"> <option value="Edge"> </datalist>
Number & range
A number input takes a typed value; a range is a slider. Both accept min, max, and step.
<label for="qty">Quantity</label>
<input type="number" id="qty" name="qty" min="1" max="10">
<label for="rating">Rating: <output id="rangeOut">3</output></label>
<input type="range" id="rating" name="rating" min="0" max="5" value="3"
oninput="document.getElementById('rangeOut').value = this.value">
<output> like the live demo does.Date, time, month, week & color
These give a native picker instead of free typing — fewer errors, less effort.
<label for="date">Reservation date</label> <input type="date" id="date" name="date"> <label for="time">Appointment time</label> <input type="time" id="time" name="time"> <label for="month">Billing month</label> <input type="month" id="month" name="month"> <label for="week">Billing week</label> <input type="week" id="week" name="week"> <label for="color">Favorite color</label> <input type="color" id="color" name="color" value="#f59e0b">
File, hidden & image inputs
hidden input is here too — it submits data the user doesn't see.<label for="file">Profile picture</label> <input type="file" id="file" name="file" accept="image/*"> <input type="hidden" name="userId" value="12345"> <input type="image" src="submit.png" alt="Submit">
method="POST" and enctype="multipart/form-data" on the form. Hidden fields are not secret — they're visible in the page source, so never put passwords there.Submit, reset & button
type="submit" sends the form, type="reset" clears it, and type="button" does nothing on its own — it's for actions you wire up with JavaScript.
<button type="submit" class="btn-primary">Submit</button>
<button type="reset" class="btn-ghost">Reset</button>
<button type="button" class="btn-ghost" onclick="alert('Hello from a type=button!')">Click me</button>
<style>
button {
font-family: inherit; font-size: .92rem; font-weight: 600; padding: 9px 18px;
border-radius: 8px; border: 0; cursor: pointer;
}
.btn-primary { background: #f59e0b; color: #1d1d1f; }
.btn-ghost { background: #f5f5f7; color: #1d1d1f; border: 1px solid #d2d2d7; }
</style>
Every input type at a glance
| type | What it's for |
|---|---|
text | Single line of plain text. |
email | Email address; checks for @ format. |
password | Masked secret text. |
tel | Phone number; number pad on mobile. |
url | Web address; requires valid URL. |
search | Search query (often shows a clear "×"). |
number | Numeric value with optional min/max/step. |
range | Slider between min and max. |
checkbox | Independent on/off option(s). |
radio | One choice from a named group. |
date / time | Native date / time picker. |
month / week | Pick a month or week. |
color | Color picker, returns a hex value. |
file | Upload one or more files. |
hidden | Data sent without being shown. |
image | Graphical submit button. |
submit / reset | Send or clear the form. |
Accessible forms
Forms are where accessibility matters most, because the user has to act. A few habits cover almost everything.
- Label every control with
for/id— no unlabeled fields, ever. - Mark required fields with the
requiredattribute and text (e.g. "Email (required)") — never color alone. - Write clear errors that say which field and how to fix it; tie them to the field with
aria-describedby. - Help autofill with sensible
autocompletevalues (name,email,tel). - Keyboard & focus: every control reachable by Tab with a visible focus outline.
<label for="email">Email (required)</label>
<input type="email" id="email" name="email"
autocomplete="email" required
aria-describedby="email-help">
<p id="email-help">We'll only use this to reply.</p>