HTML & CSS

HTML Forms

Forms are how users send data to a site — logging in, signing up, searching, booking, contacting. Here's every input control with a live demo, the labels that make them usable, and the habits that keep them accessible.

New to forms? Read the visual lesson →
Watch first

Demo: building a form

A short walkthrough of the controls on this page and how to label them. The video will go here.

Demo video coming soon Forms walkthrough will be embedded here.
The basics

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 vs. name: id links an input to its <label> in the browser; name identifies the field in the submitted data. Most inputs want both.
Most important habit

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">
Placeholder is not a label. It vanishes when typing and is often skipped by assistive tech. Use it for an example of the format — never instead of a visible <label>.
Text controls

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>
Choices

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>.

Contact preference
<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>
Numbers

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">
Accessibility: a slider's value is invisible to many users — mirror it in an <output> like the live demo does.
Pickers

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">
Files & more

File, hidden & image inputs

A 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">
Heads up: a file upload needs 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.
Actions

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>
Use Reset sparingly. It wipes everything the user typed and is easy to hit by accident — many modern forms leave it out.
Cheat sheet

Every input type at a glance

typeWhat it's for
textSingle line of plain text.
emailEmail address; checks for @ format.
passwordMasked secret text.
telPhone number; number pad on mobile.
urlWeb address; requires valid URL.
searchSearch query (often shows a clear "×").
numberNumeric value with optional min/max/step.
rangeSlider between min and max.
checkboxIndependent on/off option(s).
radioOne choice from a named group.
date / timeNative date / time picker.
month / weekPick a month or week.
colorColor picker, returns a hex value.
fileUpload one or more files.
hiddenData sent without being shown.
imageGraphical submit button.
submit / resetSend or clear the form.
Do it right

Accessible forms

Forms are where accessibility matters most, because the user has to act. A few habits cover almost everything.

<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>
Make it real: connect a working contact form with no backend using the Formspree tutorial, and see more in the Accessibility tutorial.