Form Elements
Not every question fits in a one-line <input>. A complaint needs several lines of text, a state should be picked from a list, and a group of radio buttons needs a visible question. HTML has a dedicated element for each of these jobs.
In this lesson you will use <textarea>, <select>, <datalist>, <fieldset> and <legend>, and three elements that show values rather than collect them: <output>, <progress> and <meter>.
textarea: multi-line text
A <textarea> is a box for longer text, such as an address or a message. Unlike <input>, it has a closing tag, and any starting text goes between the tags, not in a value attribute.
rowsandcolsset the starting size in lines and characters. CSS can size it too.maxlengthlimits how many characters can be typed.- Spaces and line breaks between the tags become part of the starting text, so keep
<textarea></textarea>on one line when it should start empty.
select and option: pick from a list
A <select> shows a drop-down list. Each choice is an <option>. The value attribute is what gets sent; the text between the tags is what the user sees. If an option has no value, its text is sent instead.
selectedchooses an option when the page loads.<optgroup label="...">groups related options under a heading inside the list.- A first option with an empty value, such as
<option value="">Choose a state</option>, works as a prompt. Together withrequired, it forces the user to pick a real option.
datalist: suggestions, not rules
A <datalist> gives an input a list of suggestions that appear as the user types. Connect it with the input's list attribute, which must match the datalist's id. The user can still type anything, so use it when you want to help, not to restrict. To restrict choices, use <select>.
The example below uses all three elements in a complaint form for a housing society.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Society Complaint</title>
<style>label { display: block; margin-top: 12px; }</style>
</head>
<body>
<h1>Green Park Society, Lucknow: complaint form</h1>
<form action="#">
<label for="block">Your block</label>
<select id="block" name="block" required>
<option value="">Choose a block</option>
<optgroup label="North wing">
<option value="A">Block A</option>
<option value="B">Block B</option>
</optgroup>
<optgroup label="South wing">
<option value="C">Block C</option>
<option value="D">Block D</option>
</optgroup>
</select>
<label for="type">Problem type</label>
<input id="type" name="type" list="problem-types">
<datalist id="problem-types">
<option value="Water leakage"></option>
<option value="Lift not working"></option>
<option value="Street light"></option>
<option value="Parking"></option>
</datalist>
<label for="details">Describe the problem</label>
<textarea id="details" name="details" rows="4" cols="40" maxlength="500"></textarea>
<p><button>Submit complaint</button></p>
</form>
</body>
</html>Click into "Problem type" to see the suggestions, then type something that is not in the list: it is accepted. Try submitting without choosing a block: the empty first option and required stop you.
You may see <select multiple> in some forms. It lets users pick several options, but they must hold Ctrl or Cmd to do it, which many people do not know. A group of checkboxes is usually easier.
fieldset and legend: group related controls
A <fieldset> groups related controls, and its first child, <legend>, gives the group a caption. This matters most for radio buttons and checkboxes: each option has its own label, but the question they answer needs one too. Screen readers announce the legend when the user enters the group, for example "Delivery time, group".
A disabled attribute on a <fieldset> disables every control inside it at once, which is handy for sections that only apply in some cases.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Delivery Options</title>
</head>
<body>
<form action="#">
<fieldset>
<legend>Delivery time</legend>
<label><input type="radio" name="slot" value="morning" checked> Morning</label>
<label><input type="radio" name="slot" value="evening"> Evening</label>
</fieldset>
<p>
<label><input type="checkbox" id="gift-toggle"> This is a gift</label>
</p>
<fieldset id="gift" disabled>
<legend>Gift options</legend>
<label for="msg">Message for the card</label>
<input id="msg" name="gift-message">
<label><input type="checkbox" name="wrap" value="yes"> Gift wrap (₹49)</label>
</fieldset>
<p><button>Continue</button></p>
</form>
<script>
document.querySelector("#gift-toggle").addEventListener("change", (event) => {
document.querySelector("#gift").disabled = !event.target.checked;
});
</script>
</body>
</html>Tick "This is a gift" and the whole gift section becomes usable. The tiny script only flips the fieldset's disabled property.
output, progress and meter: showing values
These three elements display information instead of collecting it.
<output>shows the result of a calculation. Itsforattribute lists the ids of the inputs it was calculated from. It acts as a status region, so most screen readers announce its new value when it changes.<progress>shows how far a task has got, such as an upload or a multi-step form. Setvalueandmax. Without avalue, it shows an "in progress" animation for tasks whose length is unknown.<meter>shows a measurement inside a known range, such as storage used or a battery level.minandmaxset the range;low,highandoptimumdescribe which part of the range is good or bad, and many browsers colour the bar to match.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bill Splitter</title>
</head>
<body>
<h1>Split the cafe bill</h1>
<form action="#" id="split">
<label for="bill">Bill (₹)</label>
<input id="bill" type="number" min="0" value="1200">
<label for="friends">Friends</label>
<input id="friends" type="number" min="1" value="4">
<p>Each person pays: ₹<output id="share" for="bill friends">300</output></p>
</form>
<p>
<label for="profile">Profile complete</label>
<progress id="profile" value="3" max="5">3 of 5 steps</progress>
</p>
<p>
<label for="storage">Phone storage used</label>
<meter id="storage" min="0" max="128" low="80" high="110" optimum="20" value="118">118 GB of 128 GB</meter>
</p>
<script>
const form = document.querySelector("#split");
form.addEventListener("input", () => {
const bill = Number(form.bill.value);
const friends = Number(form.friends.value) || 1;
document.querySelector("#share").textContent = (bill / friends).toFixed(2);
});
</script>
</body>
</html>Change the bill or the number of friends and the <output> updates. The storage meter shows a warning colour in many browsers, because 118 is above the high mark and far from the optimum. The text inside <progress> and <meter> is a fallback for very old browsers.
Use <progress> for "how much is done" and <meter> for "how much there is". A meter is never used for a loading bar.
disabled or readonly?
Both attributes stop the user from changing a field, but they behave differently.
disabled | readonly | |
|---|---|---|
| User can change the value | No | No |
| Can be focused and selected | No | Yes |
| Value is sent with the form | No | Yes |
| Looks greyed out | Usually | No |
| Works on | All form controls | Text-like inputs and <textarea> |
Use readonly for a value the user should see and submit but not edit, such as a fixed order number. Use disabled for a field that does not apply right now. Remember that neither attribute is security: anyone can change the value in the developer tools, so the server must check it.
Common mistakes
- Putting starting text in a
valueattribute on<textarea>. Put it between the tags. - Expecting
<datalist>to block other answers. It only suggests; use<select>to restrict. - Radio groups without a
<fieldset>and<legend>. The options are labelled, but the question is not. - Using
disabledon a field you still need on the server. Disabled fields are not sent; usereadonly. - Using
<meter>as a loading bar. Use<progress>.
Key points
<textarea>collects multi-line text; its starting text goes between the tags.<select>restricts the answer to its options;<datalist>only suggests.<fieldset>and<legend>give a group of controls a shared caption, anddisabledon a fieldset disables the whole group.<output>shows a calculated result,<progress>shows how much of a task is done, and<meter>shows a measurement in a range.disabledfields are not submitted;readonlyfields are.
Exercise
Build a "Course feedback" form with: a <select> for the course (HTML, CSS, JavaScript) with a "Choose a course" prompt option and required, a <fieldset> with the legend "How was the pace?" containing three radio buttons, a <textarea> for comments limited to 300 characters, and a readonly input showing the batch code "JPR-OCT-26".
Show solution
<form action="#">
<label for="course">Course</label>
<select id="course" name="course" required>
<option value="">Choose a course</option>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
</select>
<fieldset>
<legend>How was the pace?</legend>
<label><input type="radio" name="pace" value="slow"> Too slow</label>
<label><input type="radio" name="pace" value="right" checked> Just right</label>
<label><input type="radio" name="pace" value="fast"> Too fast</label>
</fieldset>
<label for="comments">Comments</label>
<textarea id="comments" name="comments" rows="4" maxlength="300"></textarea>
<label for="batch">Batch code</label>
<input id="batch" name="batch" value="JPR-OCT-26" readonly>
<button>Send feedback</button>
</form>The batch code uses readonly, not disabled, so it is still sent with the form.
Quick Quiz
1. Where does the starting text of a <textarea> go?
<textarea> has no value attribute; its default text is its content.
2. A user types a city that is not in a <datalist>. What happens?
A datalist only suggests values; it never restricts what can be typed.
3. Which field is sent when the form is submitted?
Readonly fields are submitted; disabled fields are left out.
4. Which element fits "4 of 10 videos watched"?
Progress shows how much of a task is complete; meter is for a measurement within a range.
Learn HTML with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
