Runnable lesson · press Try it on the examples to edit and run them here.
Attributes in JSX look like HTML attributes, but they turn into props (properties) passed to an element or component. This lesson covers the cases you will meet every day.
String values and expression values
Use quotes for a fixed string, and braces for anything calculated:
function App() {
const user = { name: "Ada", avatar: "https://example.com/ada.png" };
return (
<section>
<h2 title="A fixed string">{user.name}'s profile</h2>
<a href={"https://example.com/users/" + user.name.toLowerCase()}>Open profile</a>
</section>
);
}
Do not put quotes around braces. src="{url}" passes the literal text {url}; src={url} passes the value of url.
className, not class
class is a reserved word in JavaScript, so JSX uses className:
function App() {
return (
<div>
<style>{`.box { padding: 12px; background: #fff3e0; border-radius: 8px; }`}</style>
<div className="box">Styled box</div>
</div>
);
}
(We put a <style> element in the example to keep it in one file. In a project you would import a CSS file; see CSS Stylesheets.)
htmlFor, not for
for is also reserved, so a <label> uses htmlFor to point at the input’s id:
function App() {
return (
<div>
<label htmlFor="email">Email</label>
<input id="email" type="email" />
</div>
);
}
The style attribute takes an object
In HTML, style is a string. In JSX it is a JavaScript object with camelCase keys. That is why you see two pairs of braces: the outer pair opens JavaScript, the inner pair is the object.
function App() {
return (
<p style={{ color: "white", backgroundColor: "#c0392b", padding: "8px 12px", fontSize: 18 }}>
Warning!
</p>
);
}
Numbers become px for most properties (fontSize: 18 is 18px). Properties that are not lengths, such as opacity or lineHeight, stay unitless.
Boolean attributes
Writing the name alone means true. Passing false removes the attribute:
function App() {
const locked = true;
return (
<div>
<input aria-label="Name" placeholder="Editable" />
<input aria-label="Locked" placeholder="Disabled" disabled />
<button disabled={locked}>Disabled</button>
</div>
);
}
data- and aria- attributes keep their hyphens
<button data-testid="save" aria-label="Save changes">Save</button>
Always give icon-only buttons an aria-label, so screen readers know what they do.
Spreading attributes
If you have an object of props, spread it with {...object}:
function App() {
const common = { type: "button", className: "btn", title: "Click me" };
return <button {...common}>Spread button</button>;
}
Use spread with care. It is convenient, but it makes it harder to see what a component receives. Passing Props returns to this.
Event attributes take functions
function App() {
const [message, setMessage] = React.useState("");
return (
<div>
<button onClick={() => setMessage("Hi!")}>Say hi</button>
<p>{message}</p>
</div>
);
}
Pass the function itself: onClick={handleClick}. Do not call it: onClick={handleClick()} runs it during rendering. Click Events explains this.
Common mistakes
classandforinstead ofclassNameandhtmlFor.style="color: red"(a string) instead ofstyle={{ color: "red" }}.- Quotes around braces:
value="{count}". - CSS property names in kebab-case inside the style object: use
backgroundColor, notbackground-color.
Key points
- Quotes for fixed strings, braces for expressions.
className,htmlFor, camelCase events, and an object forstyle.- Boolean attributes: name alone is
true;{false}removes it.