The idea
Forms are how users talk back to a website: searching, signing up, checking out, filtering a report. HTML gives you a lot for free if you use the right elements: mobile keyboards that match the input, validation without JavaScript, and forms that work with screen readers. Get the markup right and most of the hard work is already done.
A form and its fields
Toko Kita wants a newsletter sign-up box: a name, an email address and a button. That's the simplest useful form, and it already shows every part a form needs:
<form action="/subscribe" method="post">
<label for="name">Name</label>
<input id="name" name="name" type="text" autocomplete="name">
<label for="email">Email</label>
<input id="email" name="email" type="email" required autocomplete="email">
<button type="submit">Subscribe</button>
</form>
<form action method>: where the data goes and how.getputs it in the URL (searches, filters);postsends it in the request body (sign-ups, anything that changes data).<input>: a field. Itsnameis the key the server receives ([email protected]).<label for="email">: the field's visible name. Itsformatches the input'sid.<button type="submit">: sends the form.
Every input needs a label. Clicking the label focuses the field (a bigger target, especially on phones), and screen readers read the label when the field is focused. A placeholder is not a label: it disappears as soon as you type and is often low-contrast.
Input types
The type changes the keyboard, the built-in validation and sometimes the whole control:
<form>
<p><label for="qty">Quantity</label> <input id="qty" name="qty" type="number" min="1" max="10" value="1"></p>
<p><label for="phone">Phone</label> <input id="phone" name="phone" type="tel"></p>
<p><label for="date">Delivery date</label> <input id="date" name="date" type="date"></p>
<p><label for="pw">Password</label> <input id="pw" name="pw" type="password" minlength="8"></p>
<p><label for="q">Search</label> <input id="q" name="q" type="search"></p>
</form>
| Type | You get |
|---|---|
email | email keyboard on phones, checks for an @ |
number | number keyboard, up/down buttons, min/max/step |
tel | phone keypad (no format check: phone formats vary) |
date | a date picker |
password | hidden characters |
checkbox, radio | tick boxes and single-choice buttons |
Choices: select, radio, checkbox
Not every answer is typed. When a customer orders coffee beans, they pick a grind from a list, choose one roast out of three, and maybe tick a couple of extras. Each kind of choice has its own control:
<form>
<label for="grind">Grind</label>
<select id="grind" name="grind">
<option value="whole">Whole beans</option>
<option value="coarse">Coarse (French press)</option>
<option value="fine" selected>Fine (espresso)</option>
</select>
<fieldset>
<legend>Roast</legend>
<label><input type="radio" name="roast" value="light"> Light</label>
<label><input type="radio" name="roast" value="medium" checked> Medium</label>
<label><input type="radio" name="roast" value="dark"> Dark</label>
</fieldset>
<label><input type="checkbox" name="gift" value="yes"> Gift wrap</label>
<label for="note">Note for the roaster</label>
<textarea id="note" name="note" rows="3"></textarea>
</form>
<select>with<option>s: a dropdown.valueis what's sent; the text is what's shown;selectedsets the default.- Radio buttons share a
name, so only one can be chosen. Group them in a<fieldset>with a<legend>, which acts as the group's label. - Checkboxes are independent yes/no choices.
- Wrapping an input inside its
<label>is the other way to connect them, with nofor/idneeded. <textarea>for multi-line text.
Validation built in
People make typos, leave fields empty and type letters where you wanted numbers. You could write JavaScript to check every field, but for most rules you don't have to. Add a few attributes and the browser checks the form before it's sent, and shows the user what's wrong:
<form>
<label for="code">Voucher code (6 letters or digits)</label>
<input id="code" name="code" required pattern="[A-Z0-9]{6}" maxlength="6">
<label for="amount">Amount (Rp)</label>
<input id="amount" name="amount" type="number" min="10000" step="1000" required>
<button>Apply</button>
</form>
required, min, max, minlength, maxlength, step, pattern and the input type are checked by the browser before the form is sent, with an error message in the user's language. JavaScript can ask too: input.checkValidity() returns true or false.
Browser validation is for user convenience. Anyone can bypass it, so the server must always validate again (as you did in the Flask track).
Every field gets a name and a <label>; pick the most specific type; group radio buttons with fieldset/legend; use required, min/max and pattern for instant feedback, and validate again on the server.
Why this matters for clean code
A well-marked-up form needs very little JavaScript: the browser handles keyboards, validation and accessibility. Every attribute you add (type="email", required, autocomplete="email") is a line of JavaScript you don't have to write, test and maintain.
Recap
<form action method>:getfor searches,postfor changes.- Inputs need
name(the data key) and a<label>(viafor/idor wrapping). Placeholders aren't labels. - Types:
email,number,tel,date,password,search,checkbox,radio. <select>/<option>, radios sharing anameinside<fieldset>+<legend>,<textarea>.required,min,max,pattern... for browser validation; always validate on the server too.