JSX Attributes
Table of Contents + −
In the last lesson you learned Embedding Expressions in JSX. Now let’s look at attributes, the settings you put on a tag (like the source on an <img>), which work a little differently in JSX than in HTML.
🤔 Why JSX Attributes Matter
Here is the pain you hit when you copy HTML straight into a React file:
- It has
class="card"on it, plus a<label for="email">and astyle="color: red". You expect it to just work. - Instead React warns you. Or the style never shows up.
- So now you are stuck wondering why your perfectly good HTML broke.
The fix is simple once you know it:
- JSX looks like HTML but it is really JavaScript. So a few attribute names change.
- Dynamic values use curly braces instead of quotes.
- Learn the handful of differences and the warnings go away.
🔖 What Is a JSX Attribute?
An attribute is extra information you attach to a tag. It tells the tag how to behave. Think of a light switch. The switch itself is the tag. Whether it is set to on or off, what room it controls, what color the plate is. All of that is the switch’s attributes.
In JSX, attributes show up in two places:
- Every HTML-like tag can take them, like
typeon an<input>. - Your own components take them too. There we call them props.
The rules below cover both.
📝 String Values Go in Quotes
When the value of an attribute is a fixed piece of text, you write it in double quotes. This is exactly like HTML.
function SignupField() { return <input type="text" placeholder="Enter your name" />;}Here is what each part does:
type="text"tells the input it is a text box.placeholder="Enter your name"is the grey hint text shown when the box is empty.- Both values are plain fixed strings, so plain quotes are all you need.
The thing to remember is this. Quotes are only for text you are typing by hand that will not change.
🔢 Dynamic Values Go in Curly Braces
Now what if the value is not fixed?
- Say the image URL comes from a variable, or the button text depends on data.
- You cannot put a variable inside quotes. If you do, it is just the literal word.
- So for any value that comes from JavaScript, you swap the quotes for curly braces.
function Avatar() { const imageUrl = "https://i.pravatar.cc/100"; const altText = "User profile photo";
return <img src={imageUrl} alt={altText} />;}Walk through it:
src={imageUrl}reads the value of theimageUrlvariable and uses it as the source.alt={altText}does the same for the alt text.- The curly braces mean “run this JavaScript and use the result”.
So anything that is a string literal stays in quotes. Anything from a variable, a function call, or any expression goes in braces.
Tip
Easy rule of thumb: quotes for fixed text, braces for anything dynamic. Never wrap a variable in quotes like src="imageUrl", or React uses the literal text “imageUrl” as the source.
🎨 className Instead of class
In HTML you set CSS classes with class. In JSX you write className instead.
- The reason is that
classis already a reserved word in JavaScript. - And JSX is JavaScript, so React picked a different name to avoid the clash.
function Card() { return <div className="card shadow rounded">Hello</div>;}You can list several classes in the one string, separated by spaces, just like HTML. And because it is just an attribute, you can make it dynamic too.
function Card({ isActive }) { return <div className={isActive ? "card active" : "card"}>Hello</div>;}The value here is an expression, so it goes in braces. It picks the class based on the isActive prop.
🏷️ htmlFor Instead of for
Labels in HTML use a for attribute to point at the input they describe. In JSX you write htmlFor instead.
- The reason is the same as
className. - The word
foris already a keyword in JavaScript, the one you use to write loops.
function EmailField() { return ( <div> <label htmlFor="email">Email</label> <input id="email" type="email" /> </div> );}Here is why this matters:
- The
htmlFor="email"connects the label to the input whoseidisemail. - Now clicking the label focuses the box.
- That is great for people using screen readers or just tapping on a phone.
💅 The style Attribute Takes an Object
This part confuses almost everyone the first time. In HTML you write inline styles as a string: style="color: red; font-size: 20px". In JSX, style does not take a string. It takes a JavaScript object.
function Warning() { return ( <p style={{ color: "red", fontSize: "20px" }}> Please fill in all fields. </p> );}Look closely at those double braces. That is the part people get wrong:
- The outer braces are the normal “here comes JavaScript” braces, the same ones you saw with
src={imageUrl}. - The inner braces are a plain JavaScript object, the kind you write with
{ key: value }. - So
style={{ ... }}is reallystyle={followed by an object{ ... }. They are two different braces doing two different jobs that just happen to sit next to each other.
Inside the object, the property names are camelCased and the values are strings. So font-size becomes fontSize, and background-color becomes backgroundColor.
| CSS in HTML | Property in JSX style object |
|---|---|
font-size | fontSize |
background-color | backgroundColor |
text-align | textAlign |
border-radius | borderRadius |
Because the style value is just an object, you can pull it out into a variable too. That keeps the markup clean.
function Warning() { const warningStyle = { color: "red", fontSize: "20px" };
return <p style={warningStyle}>Please fill in all fields.</p>;}Now there is only one set of braces. That is because warningStyle is already an object sitting in a variable.
🐫 Attribute Names Are camelCase
Most JSX attributes that are more than one word are written in camelCase, not all lowercase like HTML.
- The first word is lowercase and each later word starts with a capital.
- This matters most for event handlers.
| HTML | JSX |
|---|---|
onclick | onClick |
onchange | onChange |
tabindex | tabIndex |
maxlength | maxLength |
Here is a button that uses the camelCase onClick. You pass it a function in braces.
function SaveButton() { const handleClick = () => { alert("Saved!"); };
return <button onClick={handleClick}>Save</button>;}Notice the function is passed in braces, not called:
- You write
onClick={handleClick}, notonClick={handleClick()}. - The braces hand React the function.
- React calls it later, when the click actually happens.
🧪 Putting It All Together
Here is a small profile card that uses every kind of attribute at once. It has a fixed string, a dynamic value, className, an onClick, and a style object.
function ProfileCard() { const name = "Riya"; const imageUrl = "https://i.pravatar.cc/100"; const cardStyle = { padding: "16px", borderRadius: "8px" };
const handleClick = () => { alert(`You clicked ${name}'s card`); };
return ( <div className="card" style={cardStyle} onClick={handleClick}> <img src={imageUrl} alt="Profile" /> <h2>{name}</h2> </div> );}Reading it top to bottom:
className="card"is a fixed string, so it stays in quotes.style={cardStyle}passes the object stored in thecardStylevariable.onClick={handleClick}passes the function to run on click, in braces and not called.src={imageUrl}reads the dynamic image URL from a variable.alt="Profile"is fixed text, so quotes again.
Output
On the screen you see a padded, rounded card with Riya’s photo and her name underneath. Click anywhere on the card and a small popup appears:
You clicked Riya's card⚠️ Common Mistakes
A few mistakes happen again and again. Watch for these.
- Wrapping a dynamic value in quotes. That turns it into literal text.
// ❌ Avoid: this uses the literal word "imageUrl" as the source<img src="imageUrl" />
// ✅ Good: braces read the variable's value<img src={imageUrl} />- Forgetting the double braces on
style, or passing a string.
// ❌ Avoid: style does not take a string in JSX<p style="color: red">Hi</p>
// ✅ Good: style takes an object, hence two sets of braces<p style={{ color: "red" }}>Hi</p>-
Calling the handler instead of passing it. Writing
onClick={handleClick()}runs the function right away while the page loads, not on click. Drop the parentheses. -
Using HTML names out of habit. The names
class,for, andonclickshould beclassName,htmlFor, andonClick.
✅ Best Practices
- Use quotes for fixed text and braces for anything that comes from JavaScript. That one habit covers most attributes.
- When a
styleobject gets long, pull it into a variable above the return so your markup stays easy to read. - Prefer
classNamewith real CSS files or utility classes over big inlinestyleobjects. Inline styles are handy for small, dynamic, one-off tweaks. - Always pair a
<label htmlFor="...">with an inputid. It helps everyone, and screen readers in particular.
🧩 What You’ve Learned
- ✅ Fixed text attribute values go in double quotes, just like HTML.
- ✅ Dynamic values from variables or expressions go in curly braces.
- ✅
classNamereplacesclass, andhtmlForreplacesfor, becauseclassandforare JavaScript keywords. - ✅ The
styleattribute takes a JavaScript object with camelCased properties, which is why you see double braces. - ✅ Multi-word attributes are camelCase, so
onclickbecomesonClick, and handlers are passed without calling them.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
How do you pass a dynamic value from a variable to a JSX attribute?
Why: Curly braces tell JSX to run the JavaScript and use its result; quotes would treat the value as literal text.
- 2
Why does JSX use className instead of class?
Why: Because JSX is JavaScript and class is already a keyword there, React uses className instead.
- 3
What does the style attribute take in JSX?
Why: The outer braces mean JavaScript and the inner braces are the object, so style={{ ... }} passes an object with camelCased keys.
- 4
What is wrong with onClick={handleClick()}?
Why: The parentheses call the function right away; pass it as onClick={handleClick} so React calls it only when the click happens.
🚀 What’s Next?
You can now set every kind of attribute on a JSX tag. Next we will look at how to leave notes for yourself and your team inside JSX without breaking the build.