An HTML select dropdown is a <select name="..."> containing one <option> per choice, where each option's value is submitted and its text is shown. For a placeholder, add a first option with value="" and disabled selected hidden, and put required on the select. Group long lists with <optgroup>, add multiple to allow several choices, and connect a <label>.
This guide covers building a select properly, the placeholder pattern, multiple selection, the datalist alternative for free text, styling, and reading the value in JavaScript. It's part of the HTML form elements reference.
A select dropdown in a form
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">
<label for="topic">What can we help with?</label>
<select id="topic" name="topic" required>
<option value="" disabled selected hidden>Choose a topic</option>
<option value="sales">Sales question</option>
<option value="support">Technical support</option>
<option value="billing">Billing</option>
<option value="other">Something else</option>
</select>
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
<button type="submit">Send</button>
</form>If someone picks "Technical support", the form submits topic=support. The text is for people, and the value is a stable key for you. If an option has no value attribute, its text is submitted instead, which is fine for simple lists but breaks if you later reword the text.
Option and optgroup
<option> attributes you'll use:
| Attribute | What it does |
|---|---|
value | What's submitted when this option is selected. |
selected | Pre-selects this option. Without it, the first option is selected. |
disabled | Shown but can't be chosen. |
label | Alternative display text. Rarely needed. |
<optgroup label="..."> groups options under a heading that can't be selected. It's useful for long lists:
<label for="service">Service</label>
<select id="service" name="service">
<optgroup label="Design">
<option value="branding">Branding</option>
<option value="web-design">Web design</option>
</optgroup>
<optgroup label="Development">
<option value="frontend">Front-end</option>
<option value="backend">Back-end</option>
</optgroup>
</select>Optgroups can't be nested. Use them for one level of grouping only.
The placeholder option pattern
A select always has a value. Without a placeholder, the first real option is pre-selected, and people who skip the field submit it without meaning to. The fix is a placeholder option:
<option value="" disabled selected hidden>Choose a topic</option>Each attribute does one job:
value=""makes the placeholder an empty answer, sorequiredtreats it as "nothing chosen".selectedshows it when the page loads.disabledstops people from re-selecting it after picking a real option.hiddenkeeps it out of the open list in browsers that support it. It's optional.
For required to work with the placeholder, the placeholder must be the first option, and the select must not have multiple or a size greater than 1. Keep a visible <label> as well. The placeholder text disappears once something is chosen.
Multiple selection and size
multiple turns the dropdown into a list box where several options can be selected:
<label for="languages">Languages you speak</label>
<select id="languages" name="languages" multiple size="5">
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="hi">Hindi</option>
</select>size sets how many rows are visible. A multi-select sends one name=value pair per selected option, for example languages=en&languages=fr, and FormSubmit keeps multiple values for the same name.
On desktop, selecting several options needs Ctrl or Cmd held down, which many visitors don't know and which is easy to undo by accident. For fewer than about ten options, checkboxes are usually clearer. For a single choice from a handful of options, radio buttons show everything at once.
Datalist: suggestions with free text
A select only allows its listed options. When most people will pick a common answer but some need to type their own, use an input with a <datalist>:
<label for="role">Job title</label>
<input id="role" name="role" list="roles">
<datalist id="roles">
<option value="Founder"></option>
<option value="Developer"></option>
<option value="Designer"></option>
<option value="Marketing manager"></option>
</datalist>The browser shows matching suggestions as people type, and the input submits whatever ends up in the box. Datalist presentation varies a lot between browsers, so treat it as a convenience, not a guarantee of valid input.
Styling a select
Native selects are hard to style consistently. This removes the platform look and adds a custom arrow while keeping the native control:
select {
appearance: none;
box-sizing: border-box;
width: 100%;
padding: 0.625rem 2.5rem 0.625rem 0.75rem;
font: inherit;
color: inherit;
background-color: #fff;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%236b7280'%3E%3Cpath d='M5.3 7.3a1 1 0 0 1 1.4 0L10 10.6l3.3-3.3a1 1 0 1 1 1.4 1.4l-4 4a1 1 0 0 1-1.4 0l-4-4a1 1 0 0 1 0-1.4z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 1.25rem;
border: 1px solid #c4c9d4;
border-radius: 0.5rem;
}
select:focus-visible {
outline: 2px solid #4f46e5;
outline-offset: 2px;
}
select[multiple] {
background-image: none;
padding-right: 0.75rem;
}appearance: noneremoves the native arrow and styling so your own can replace it.- Right padding stops long option text from running under the arrow.
font: inheritmatches the rest of your form.- The open list of options is still drawn by the browser or operating system. On phones that's a native picker, which is a good thing for usability.
Some browsers now support fully customisable selects, where the open list can be styled with CSS. Support is limited, so treat it as progressive enhancement on top of the styles above.
Reading a select in JavaScript
const select = document.getElementById("topic");
// The selected value ("" while the placeholder is showing)
console.log(select.value);
// The visible text of the selected option
console.log(select.selectedOptions[0]?.text);
// All selected values in a multi-select
const languages = [...document.getElementById("languages").selectedOptions]
.map((option) => option.value);
// Or via FormData, which matches what would be submitted
const values = new FormData(select.form).getAll("languages");
// React to changes
select.addEventListener("change", () => {
console.log("Topic is now", select.value);
});
// Set the selection
select.value = "billing";A common pattern is to show extra fields based on the choice, for example revealing an order number input when the topic is "billing". Toggle the hidden attribute on a wrapper and set disabled on fields that don't apply, so they aren't submitted.
Sending the selected option
The chosen option arrives as a normal field, such as topic: support, so you can see at a glance what each message is about. Point the form at https://formsubmit.app/f/YOUR_FORM_ID with method="POST" and every submission is stored, spam-filtered and emailed to you. The full walkthrough is in how to send an HTML form to email. For other field types, see HTML input types or the HTML form elements overview.