<option>
Declares one choice inside a dropdown, carrying the value submitted with the form.
<select>
<option value="someOption">Some option</option>
<option value="otherOption">Other option</option>
</select>Parameters
| Parameter | Type | Description |
|---|---|---|
$valueoptional | string | The value to be used when submitting the parent <select> in a form if this option is selected. It is also the string the parent's value or defaultValue is matched against. |
$childrenoptional | ReactNode | The text shown for this choice. Used as the option's label when no label prop is given. |
$labeloptional | string | Specifies the meaning of the option. If not specified, the text inside the option is used. |
$disabledoptional | boolean= false | If true, the option will not be selectable and will appear dimmed. |
$...propsoptional | HTMLOptionElement props | <option> supports all common element props, including ref, className and style. It does not support selected. |
Return value
ReactElementRenders a browser <option> element inside a <select>, <optgroup> or <datalist>.
Errors
React does not support the selected attribute on <option> and logs an error when it is passed; set the parent <select value> or <select defaultValue> instead.
An <option> is a leaf: it declares a choice and the string that choice submits. It never decides whether it is selected — that belongs to the parent <select> through value or defaultValue. The selected attribute you would write in HTML is unsupported in React and produces an error, which is the single most common surprise on this element.
Practical rules
- Give every option an explicit
value. Without one the browser falls back to the option's text, so renaming a label silently changes what the form submits. - Values are strings. An option built from a numeric id needs
value={String(id)}, or the comparison against the select'svaluequietly fails and the box renders blank. - When mapping over data,
keyandvalueare different props with different jobs —keyis for React's reconciler and never reaches the DOM. labeloverrides the child text in the popup on some browsers; leave it off unless you deliberately want two different strings.- A placeholder is an ordinary option with
value="", usually markeddisabledso the user cannot return to it, and paired withrequiredon the select.
Example
When to use it
- Render a dropdown's choices by mapping over an array of records
- Add a disabled 'Choose one' placeholder so a required select starts empty
- Group and dim options that are unavailable, such as sold-out sizes
Frequently asked questions
How do I mark an option as selected in React?
You do not set it on the option. Pass that option's value string to the parent select — <select defaultValue="m"> for an uncontrolled dropdown or <select value={size}> for a controlled one. React explicitly does not support the selected attribute on <option> and errors when it sees one.
Do I need a value on every option?
Practically, yes. An option without a value submits its own text content, so any change to the visible label changes the submitted data. It also has to match the parent select's value exactly for the right option to appear selected, and matching against display text is fragile.
How do I add a placeholder to a select?
Render a first <option value="" disabled> with your placeholder text and start the select's value at the empty string. Adding required to the select then blocks submission until a real choice is made, and disabled stops the user from returning to the placeholder.
More examples
Options from data, with numeric ids
The dropdown opens on Grace Hopper and the paragraph reads `Assigned to Grace Hopper (id 12)`. State holds a real number, but the DOM only speaks strings, so the value prop is stringified on the way in and the change handler parses on the way out. Skipping either conversion is the usual cause of a select that renders blank or a lookup that returns undefined, because 12 and "12" never match with ===.
import { useState } from "react";
const USERS = [
{ id: 7, name: "Ada Lovelace" },
{ id: 12, name: "Grace Hopper" },
{ id: 19, name: "Alan Turing" },
];
export default function AssigneePicker() {
const [assigneeId, setAssigneeId] = useState(12);
const assignee = USERS.find((user) => user.id === assigneeId);
return (
<div>
<select
value={String(assigneeId)}
onChange={(e) => setAssigneeId(Number(e.target.value))}
>
{USERS.map((user) => (
<option key={user.id} value={String(user.id)}>
{user.name}
</option>
))}
</select>
<p>Assigned to {assignee.name} (id {assigneeId})</p>
</div>
);
}label and children are not the same thing
The dropdown opens on the middle option because the parent's defaultValue is "m". That option carries both children ("Medium") and a label prop; browsers that honour label show "Medium (recommended)" in the popup while the children remain the fallback, so the two strings can disagree. The third option is dimmed and unselectable but still present in the markup, which is how you show an unavailable choice rather than hiding it.
export default function SizeLegend() {
return (
<select defaultValue="m">
<option value="s">Small</option>
<option value="m" label="Medium (recommended)">
Medium
</option>
<option value="l" disabled>
Large — out of stock
</option>
</select>
);
}
Discussion