htmlFor
Link a label to a form control by id; htmlFor is JSX's name for the HTML for attribute.
<label htmlFor={string}>Parameters
| Parameter | Type | Description |
|---|---|---|
$htmlForoptional | string | On <label>, the id of the control the label describes. On <output>, a space-separated list of ids of the elements whose values contributed to the result. |
for is a reserved word in JavaScript, so React uses the DOM property name htmlFor. It applies to <label> and <output>, and its value is an element id — not a name, not a ref.
Why it matters
- Clicking the label text focuses the field, and toggles a checkbox or radio. That is a much bigger hit target, which matters most on touch.
- Assistive technology reads the label as the field's accessible name. Without the association, a screen reader announces an unlabelled edit field.
What trips people up
Hard-coded ids collide the moment the component is rendered twice on a page — two id="email" fields, and every label points at the first one. Generate ids with useId and suffix them per field.
The alternative is to nest the input inside the label, which needs no id at all. That is the simplest correct option when the markup allows it; use htmlFor when your layout puts the label and the control in different containers.
Placeholder text is not a label: it disappears on typing and is not reliably announced.
Example
When to use it
- Making a checkbox toggle when its text is clicked
- Labelling fields in a component that can appear more than once per page
- Wiring a label to a control that sits in a separate grid cell
- Pointing an <output> at the inputs whose values it summarizes
Frequently asked questions
Why doesn't for work on a label in JSX?
Because for is a reserved word in JavaScript, so React exposes the DOM property name htmlFor instead. Write htmlFor={id} and the rendered HTML will contain a normal for attribute.
How do I generate unique ids for form fields in React?
Call useId inside the component and build ids from it, such as id + "-email". It produces values that are stable across server and client rendering, unlike a random number or a module-level counter.
Do I need htmlFor if the input is inside the label?
No — nesting the control inside the label associates them implicitly, and clicking the text still focuses the field. Use htmlFor when the layout separates them, for example in a grid where the label and input are different cells.
More examples
A reusable field that generates its own id
Each Field calls useId, so the two instances get distinct ids and their labels and hints point at the right controls. The same generated id is reused as a prefix for the hint element referenced by aria-describedby. useId values are stable between server and client render, which is what makes them safe for hydrated markup — Math.random() or a module counter would mismatch.
import { useId } from "react";
function Field({ label, hint, type = "text" }) {
const id = useId();
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} type={type} aria-describedby={hint ? id + "-hint" : undefined} />
{hint ? <small id={id + "-hint"}>{hint}</small> : null}
</div>
);
}
export default function SignupForm() {
return (
<form>
<Field label="Email" type="email" hint="We never share it." />
<Field label="Password" type="password" hint="At least 12 characters." />
</form>
);
}htmlFor on <output>
On <output>, htmlFor takes a space-separated list of the ids that fed the result, so assistive technology can report which fields the value 5 came from. It is the same prop name as on <label> but a different meaning: a list of contributors rather than a single target.
import { useId, useState } from "react";
export default function Calculator() {
const id = useId();
const [a, setA] = useState(2);
const [b, setB] = useState(3);
return (
<form onSubmit={(e) => e.preventDefault()}>
<input id={id + "-a"} type="number" value={a} onChange={(e) => setA(Number(e.target.value))} />
{" + "}
<input id={id + "-b"} type="number" value={b} onChange={(e) => setB(Number(e.target.value))} />
{" = "}
<output htmlFor={id + "-a " + id + "-b"} name="sum">{a + b}</output>
</form>
);
}
Discussion