HTML Select Element
A dropdown is one of the oldest and most familiar controls on the web. You click, a list opens, you choose, and the list closes again. It saves space, it works on every device, and on phones it opens a native picker that people already know how to use. In HTML, the dropdown is the <select> element, filled with <option> elements.
The idea is easy, but choosing well takes thought: when is a dropdown better than radio buttons? How do you stop a visitor from "answering" without choosing? What gets sent? In this lesson, you will learn all of that, and how to build dropdowns that depend on each other.
What You Will Learnβ
- How
<select>and<option>work together - What is sent to the server
- The placeholder option pattern, with
required - Choosing several options with
multipleandsize - The
changeevent, and dependent dropdowns - When to use a select, radios, or something else
- Keyboard use, styling limits, accessibility, and common mistakes
The Basicsβ
- HTML Code
- Browser Output
<label for="country">Country</label>
<select id="country" name="country">
<option value="in">India</option>
<option value="ng">Nigeria</option>
<option value="br">Brazil</option>
<option value="de">Germany</option>
</select>
The pieces:
<select>is the control. Itsnameis the key sent to the server.<option>is one choice. The text between its tags is what the visitor reads. Itsvalueis what the server receives.- A
<label>connects to the select withforandid, exactly like for an input (see Label Element).
You will study <option>, and grouping with <optgroup>, in detail in Option and Optgroup. This lesson focuses on the <select> itself.
What Is Sentβ
For a normal dropdown, the browser sends name=value of the chosen option:
country=ng
| Situation | What is sent |
|---|---|
An option has a value | That value (such as ng) |
An option has no value | The option's text (such as Nigeria) |
The <select> has no name, or is disabled | Nothing |
| A normal dropdown | Always one choice, because the first option is chosen from the start |
That last row matters, and the next section explains why.
The Placeholder Optionβ
A normal single dropdown always has something selected. If you do not choose a starting option, the browser picks the first one. So a visitor can submit the form without ever touching the dropdown, and "India" is sent, as if they had chosen it. That is bad for data quality.
The fix is a placeholder option: a first option with an empty value, plus required.
- HTML Code
- Browser Output
<label for="country">Country</label>
<select id="country" name="country" required>
<option value="">Choose a country</option>
<option value="in">India</option>
<option value="ng">Nigeria</option>
<option value="br">Brazil</option>
<option value="de">Germany</option>
</select>
Press Submit without choosing: the browser stops the form with "Please select an item in the list." That works because required fails when the chosen option has an empty value.
Details to get right:
- The placeholder must have
value=""(an empty value). Leaving outvaluealtogether does not work, since the text would then be used as the value. - It must be the first option, so it is selected by default.
- Write it as an instruction: "Choose a country," not "Country." Without
required, a visitor who leaves it will send an emptycountry=, which your server should treat as "no answer." - You may add
disabledandselectedto the placeholder, so it cannot be picked again once the visitor has chosen.requiredstill works with it. The trade-off is that a visitor cannot go back to "no choice," so many teams prefer a plain, enabled placeholder.
<option value="" disabled selected>Choose a country</option> <!-- common variation -->
Try It: See What Is Sentβ
The first dropdown uses the placeholder pattern. The second allows several choices. Try both, and press Submit.
- HTML Code
- Browser Output
<form>
<label for="country">Country</label>
<select id="country" name="country" required>
<option value="">Choose a country</option>
<option value="in">India</option>
<option value="ng">Nigeria</option>
<option value="br">Brazil</option>
<option value="de">Germany</option>
</select>
<label for="langs">Languages you speak</label>
<select id="langs" name="lang" multiple size="4">
<option value="en" selected>English</option>
<option value="hi">Hindi</option>
<option value="pt">Portuguese</option>
<option value="de">German</option>
</select>
<button type="submit">Submit</button>
</form>
Notice:
- Choosing two languages sends
lang=en&lang=hi: the same name repeats, once per selected option, just like a group of checkboxes. - If you unselect every language, nothing is sent for
lang. - In the demo, the page checks
requireditself because the form is not really submitted. In a real page, the browser shows its own message.
Choosing Several: multiple and sizeβ
| Attribute | What it does |
|---|---|
multiple | Lets the visitor choose more than one option |
size | How many rows are visible at once (the default is 1, which gives a dropdown) |
<select name="lang" multiple size="4">
...
</select>
- With
multiple, the control turns into a list box (all rows visible, with a scrollbar if needed). Thesizesets how many rows show. - You can also use
size="5"withoutmultiple, for a visible list where only one option can be chosen. - To pick several options, the visitor must hold
Ctrl(orCmdon a Mac) while clicking, orShiftto select a range. On a phone, they tap several in a pop-up list.
Many people do not know about the Ctrl or Cmd trick, and one wrong click without it wipes out all their choices. For a short list (up to about 7 options), a group of checkboxes is far friendlier. Use multiple for long lists, and always tell people how to pick several.
Reading the Choice in JavaScriptβ
const select = document.getElementById("country");
console.log(select.value); // "ng" (the chosen option's value)
console.log(select.selectedIndex); // 2 (its position, starting at 0)
console.log(select.selectedOptions[0].text); // "Nigeria" (the text shown)
// For a multiple select:
const chosen = [...document.getElementById("langs").selectedOptions].map((o) => o.value);
// ["en", "hi"]
You can also change the choice from code: select.value = "br".
The change Event, and Dependent Dropdownsβ
A <select> fires a change event when the visitor picks a different option. You can use it to update something else on the page. A classic use is a dependent dropdown: the list of cities depends on the country chosen.
- HTML Code
- Browser Output
<label for="country">Country</label>
<select id="country" name="country">
<option value="">Choose a country</option>
<option value="in">India</option>
<option value="ng">Nigeria</option>
<option value="br">Brazil</option>
</select>
<label for="city">City</label>
<select id="city" name="city" disabled>
<option value="">Choose a country first</option>
</select>
const cities = {
in: ["Mumbai", "Delhi", "Bengaluru"],
ng: ["Lagos", "Abuja", "Kano"],
br: ["SΓ£o Paulo", "Rio de Janeiro", "BrasΓlia"],
};
const country = document.getElementById("country");
const city = document.getElementById("city");
country.addEventListener("change", () => {
const list = cities[country.value] || [];
city.length = 0; // remove old options
city.add(new Option(list.length ? "Choose a city" : "Choose a country first", ""));
list.forEach((name) => city.add(new Option(name, name)));
city.disabled = list.length === 0;
});
Good practice for dependent dropdowns:
- Disable the second list until the first has a choice, and say why in its placeholder ("Choose a country first").
- Reset the second list whenever the first changes, so an old, no-longer-valid city cannot stay selected.
- Keep the logic on the server too. A visitor can send
country=in&city=Lagos. Check that the city belongs to the country. - For long or changing lists, load the options from the server (with
fetch) instead of writing them into your script.
When to Use a Selectβ
| Choice | Best control | Why |
|---|---|---|
| One of 2 to about 5 options | Radio buttons | All options are visible, and picking takes one click |
| One of about 6 to 15 options | Select | Saves space |
| One of a very long list (countries, languages) | Select, or an input with a datalist | Typing to find an item is quick |
| One of a huge list, with free text allowed | Input with datalist | Suggestions, but the visitor can type anything |
| Several of a short list | Checkboxes | Easier than Ctrl or Cmd clicking |
| Several of a long list | <select multiple>, or a custom checkbox list | Saves space |
| A year or a month | Select, or a number or month input | Depends on the range |
A helpful rule: if people need to compare the options, show them all. If they just need to pick one they already know ("Germany"), a dropdown is great.
Keyboard Useβ
A native select works with the keyboard without any code:
| Key | What happens |
|---|---|
Tab | Moves focus to the select |
Space, Enter, or Alt + β | Opens the list |
β / β | Moves through the options |
| Type letters (such as "ger") | Jumps to the option that starts with those letters (type-ahead) |
Enter | Chooses the highlighted option, and closes the list |
Esc | Closes the list |
Home / End | First or last option |
Type-ahead is a big reason a long, alphabetical list of countries is still usable. Keep options in a sensible order (alphabetical, or grouped), so typing finds them.
Styling Limitsβ
A <select> is one of the least styleable controls, because the browser or the operating system draws its list. You can style the closed box, but only a little of the open list.
select {
width: 100%;
max-width: 24rem;
padding: 0.6rem 2rem 0.6rem 0.75rem;
border: 1px solid #64748b;
border-radius: 6px;
background-color: #fff;
color: #0f172a;
font: inherit;
font-size: 1rem;
min-height: 2.75rem;
}
select:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
select:invalid {
color: #64748b; /* makes the placeholder look like a hint */
}
- Do not replace a select with a custom
divdropdown unless you have a strong reason. A hand-built one needs a lot of keyboard and screen reader work, and it does not get the native phone picker. font-sizeof at least 16px stops iPhones from zooming in.- To change the arrow, use
appearance: noneand add your own icon as a background image. Keep enough right padding so text does not run under it. - A newer feature,
appearance: base-select, lets browsers that support it style the whole select, including the open list. It is not available everywhere yet, so use it only as an enhancement, and keep the basic select working.
Other Attributesβ
| Attribute | What it does | Example |
|---|---|---|
name | The key sent to the server | name="country" |
id | Connects the label | id="country" |
required | A real choice is needed (see the placeholder pattern) | required |
multiple | Allows several choices | multiple |
size | Number of visible rows | size="5" |
disabled | Greyed out, and not sent | disabled |
autocomplete | Autofill hint, such as country | autocomplete="country" |
autofocus | Focus on load | autofocus |
form | Connects the select to a form it is not inside | form="checkout" |
Useful autocomplete values include country, country-name, address-level1 (state or region), bday-month, bday-year, cc-exp-month, cc-exp-year, and language. Matching the value to the option values helps browsers fill the field. For countries, use two-letter codes (such as IN) if you set autocomplete="country", and names for country-name.
There is no readonly for selects. To show a fixed value, use disabled (not sent), or plain text plus a hidden input.
Accessibility at a Glanceβ
- Always add a label, with
forandid, or by wrapping the select. - Use the native
<select>. Screen readers announce the label, the current option, and "1 of 12." Custom dropdowns rarely match that. - Write clear, short option text. Start with the most important word, so type-ahead and screen reader users can find it.
- Keep options in a logical order. Alphabetical is usually best for long lists. Put common choices first only when you are sure that helps.
- Give a clear placeholder ("Choose a country"), and use
requiredwithvalue=""to enforce a choice. - Do not change the page (navigate, submit, or move focus) on
change, unless you warn people. Keyboard users moving through options with the arrow keys would trigger it by accident. A separate "Go" button is safer. - For
multiple, explain how to select several items, and consider checkboxes instead. - Show errors in text, near the control, and not only in colour.
- Keep a visible focus style, and a large touch target.
Security and Validation Notesβ
- Re-check on the server. Anyone can send
country=anything, even a value that is not in your list. Accept only the values you defined (an allow-list). - Treat an empty value as "no answer," and handle it.
- Validate dependent fields together (for example, that the city belongs to the country).
- Never trust a hidden meaning in the value, such as a price or a role. Look it up on the server.
- Escape option text if it comes from a database and could contain
<or&.
See Secure Form Design.
Global Audience Notesβ
- Translate option text, not option values. Keep
valueas a stable code (in,ng), and translate the visible name for each language. - Sort lists using the visitor's language rules. Alphabetical order differs by language ("Γ" and "Γ" sort differently).
Intl.Collatorhelps. - Use standard codes (ISO 3166 for countries, ISO 639 for languages), so data matches across systems.
- Do not assume the set of options fits everyone. Lists of genders, titles, or states may not apply in every country. Allow "Other" or "Prefer not to say," and ask only for what you need.
- Long country lists are easier with type-ahead, so make sure the visible names start with the letters people expect, in their own language.
- Right-to-left pages show the arrow and text mirrored automatically with
dir="rtl".
Common Mistakes to Avoidβ
- No placeholder option, so the first option is sent even when the visitor never chose.
- A placeholder without
value="", sorequireddoes not work. - Leaving out
valueon options, so the visible text (which you may translate) is sent. - Using a select for 2 or 3 options, where radio buttons are quicker.
- Using
multiplefor short lists, where checkboxes are friendlier. - Not explaining
CtrlorCmdfor multiple selection. - Navigating or submitting on
change, which breaks keyboard use. - Dependent dropdowns that keep an old, invalid value.
- Trusting the value without an allow-list on the server.
- No label, or only the placeholder option as the label.
- Replacing the native select with a custom
divdropdown. - Using
readonly, which selects do not have.
Practice Timeβ
Try these in your editor:
- Build a labeled select with four options and
values. Submit it withmethod="get", and read the address. - Remove the
values from the options, and see what is sent instead. - Add a placeholder option with
value="", and then addrequired. - Leave out
value=""on the placeholder, and see ifrequiredstill works. - Add
multipleandsize="4", choose several options, and look at the address. - Use JavaScript to log
select.value,selectedIndex, andselectedOptions. - Build the country and city dependent dropdowns.
- Use only the keyboard: open, move, type-ahead, and choose.
- Style the select to match your inputs, and replace the arrow with
appearance: none. - Bonus: build the same choice as radio buttons, and decide which feels better for 4 options, and for 40.
Quick Recapβ
Click a question to check your answer.
1. What is sent when a visitor chooses an option in a select?
name=value of the chosen option. If the option has no value attribute, its visible text is sent instead.
2. Why can a normal select be submitted without the visitor choosing?
A single-choice dropdown always has an option selected, and by default it is the first. To force a real choice, add a first option with value="" and put required on the select.
3. What do multiple and size do?
multiple allows several choices, and turns the control into a list box. size sets how many rows are visible. Selected options are sent as repeated pairs, such as lang=en&lang=hi.
4. How do you update one dropdown when another changes?
Listen for the change event on the first, and rebuild the second's options (for example with new Option(...)). Disable the second until the first has a choice, and reset it each time.
5. When should you use radio buttons or checkboxes instead of a select?
Use radios for one of a few (about 5 or fewer) options, and checkboxes for several of a short list. A select is better for longer lists, where showing every option would take too much space.
6. Why should the server check a select's value?
Anyone can send a value that is not in your list. The server must accept only the values you defined, and check related fields (such as city and country) together.
Key Takeawaysβ
<select>with<option>makes a dropdown. The option'svalueis what is sent, and its text is what is shown.- A single select always has a choice. Use a first option with
value=""plusrequiredso the visitor must choose. multipleandsizemake a list box, and selected options are sent as repeated pairs. Checkboxes are easier for short lists.- Use the
changeevent for dependent dropdowns, but never navigate or submit onchangewithout warning. - Keep the native select for the keyboard, type-ahead, screen readers, and phone pickers. Styling is limited, so do not fight it.
- Translate the text, keep the values as stable codes, and always check values against an allow-list on the server.
Next, learn more about the options inside a select, and how to group them, in Option and Optgroup, or return to the Forms overview.