Topic 1.5
Inline Styles and Class Names in JSX
In one line
In JSX the style attribute takes a JavaScript object with camelCase property names (numbers become pixels for most properties), and className takes a string you can build from conditions to switch CSS classes on and off.
Think of it like this
Dressing for school. Most days you wear the uniform (a class: the same look shared by everyone, defined once). Sometimes you add a personal touch, like a badge pinned to your shirt today only (an inline style: one value on one element). In React, className picks the uniforms from your CSS file and style pins individual touches on.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- className
- The JSX attribute that sets an element's CSS classes, as one space-separated string.
- Inline style
- Styles written directly on one element with the
styleattribute. - Style object
- The object you give
style:{ fontSize: 14, color: "red" }. - camelCase CSS property
- A CSS name with dashes removed and the next letter capitalised:
backgroundColor. - Unitless property
- A CSS property whose number has no unit, like
opacity: 0.5orzIndex: 2. - CSS custom property
- A CSS variable such as
--accent, read withvar(--accent). - Conditional class
- A class name added or removed depending on data, like
doneon finished tasks. - clsx / classnames
- Tiny libraries that build a className string from conditions.
Step by step
01Start with a class from CSS
Put the shared look in CSS and refer to it by name. This is the default way to style.
// styles.css: .task { padding: 6px; } .done { text-decoration: line-through; }
<li className="task">Learn JSX</li>02Switch a class on from data
Build the string from a condition. Every render works it out again, so the class always matches the data.
<li className={done ? "task done" : "task"}>{title}</li>03Join several optional classes
With two or more optional classes, list them, drop the falsy ones and join with spaces. That's all clsx does.
function cx(...names) {
return names.filter(Boolean).join(" ");
}
cx("task", true && "done", false && "urgent"); // "task done"04Add an inline style for a computed value
A progress bar's width depends on a number that changes, so it is a good fit for style. Write the object with camelCase keys; a number becomes pixels.
<div style={{ width: progress * 3, backgroundColor: "#2f9e44" }} />
// becomes: style="width: 210px; background-color: rgb(47, 158, 68);"Try it yourself
- 1
Change the unit
In the progress bar, change
width: progress * 3towidth: progress + "%". Predict the second log line. (width: 70%;: a string is used exactly as written.) - 2
Add a class
Give
Taskatodayprop and addtoday && "today"to thecxcall, with a CSS rule.today { background: #fff9db; }. Render<Task title="Call Gran" today />. - 3
Pass a value through a CSS variable
In the progress bar, change
"--accent"to"#e03131". Only the label's colour changes, because only the label readsvar(--accent).
Code & diagrams
Compare what you wrote with what React put in the page: `width: 210` became `210px`, `opacity` and `lineHeight` kept their plain numbers, `backgroundColor` became `background-color`, and `--accent` kept its name. Change `progress` to 30 and watch the colour switch.
Preview
Console
Nothing logged yet.Expected console output
--accent: #087ea4; line-height: 1.5;
width: 210px; height: 18px; background-color: rgb(47, 158, 68); border-radius: 999px; opacity: 0.9; transition: width 0.3s;
font-size: 14px; margin-top: 6px; color: var(--accent);The template literal leaves a trailing space (`"task "`) when the condition is false; the helper produces clean strings and handles any number of optional classes. A prop written with no value, like `done`, means `done={true}`.
Preview
Console
Nothing logged yet.Expected console output
"task done" "task done"
"task " "task urgent"
"task " "task"Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Write style as a string
In the progress bar, change the label's style to style="font-size: 14px".
Break #2
Keep the CSS dash
In barStyle, change backgroundColor: to "background-color":.
Myth vs fact
Myth
Inline styles are the React way to style.
Fact
Classes are the default. Inline styles can't do hover, focus, media queries or pseudo-elements, and they're hard to override. Use them for values computed at run time.
Myth
React adds px to every number.
Fact
Only to properties that take lengths. Unitless properties (opacity, zIndex, lineHeight, flex, fontWeight…) keep the plain number, and custom properties never get a unit.
Myth
You need a library to combine class names.
Fact
[...].filter(Boolean).join(" ") does the job. clsx is a tiny convenience that adds object syntax.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
React keeps a list of unitless CSS properties (
isUnitlessNumberin react-dom) to decide when to addpx. Custom properties (names starting with--) are set withstyle.setProperty, so they never get a unit. - ▸
On updates, React compares the old and new style objects and sets or removes only the changed properties. Creating a new style object every render is fine for correctness; extracting constant styles to module scope only helps when a child is memoised and receives the object as a prop (Phase 16).
- ▸
Inline styles have the highest priority of normal declarations, only beaten by
!important. React's style object doesn't support!importantin values; if you truly need it, use a class.
Remember this
- 1
Class names are the main way to style React apps. Write CSS rules in a stylesheet (
.card { … }) and putclassName="card"on the element. Classes keep styles reusable, support hover, media queries and animations, and are fast. Phase 11 covers CSS Modules, Tailwind and other styling approaches; the/csscourse teaches CSS itself. - 2
The **
styleattribute takes an object**, not a string:style={{ color: "red", fontSize: 18 }}(the double braces from Topic 1.3). Property names are camelCase, the same names as JavaScript'selement.styleAPI:background-colorbecomesbackgroundColor,font-sizebecomesfontSize,z-indexbecomeszIndex. Values are strings ("2px solid red") or numbers. - 3
Numbers become pixels. For properties that need a length, React adds
pxto a plain number:width: 210→width: 210px,fontSize: 14→font-size: 14px. Unitless properties keep the number as it is:opacity,zIndex,lineHeight,flex,fontWeight,orderand a few others. For any other unit, write a string:width: "50%",margin: "1rem". A string number with no unit, likemarginTop: "10", is invalid CSS and the browser silently ignores it. - 4
CSS custom properties (variables) keep their exact name in quotes:
style={{ "--accent": "#087ea4" }}, used in CSS asvar(--accent). This is a neat way to pass one value from React into a whole stylesheet without inline-styling every element. - 5
Conditional class names:
classNameis just a string, so build it with JavaScript. A ternary:className={done ? "task done" : "task"}. A template literal: `className={task ${done ? "done" : ""}}(which leaves a trailing space when false; harmless, but untidy). Or **join a list**:["task", done && "done", urgent && "urgent"].filter(Boolean).join(" ")keeps only the names that are switched on. Small libraries such asclsxandclassnamesdo exactly this with an object syntax:clsx("task", { done, urgent })`. - 6
When to use which: classes for anything shared, for states (
.active,.error) and anything CSS-only (hover, focus, media queries, pseudo-elements, which inline styles can't do). Inline styles for values computed at run time that change often: a progress bar's width, a colour picked by the user, a position from a drag. Inline styles also have the highest priority in CSS, so they are hard to override from a stylesheet.
Explain it without notes
How is the style attribute in JSX different from HTML's?
When does React add px to a number in a style object?
Show two ways to add a class only when a condition is true.
When would you choose an inline style over a class?
Practice
Make a Swatch component that takes a color prop and shows a 40×40 square of that colour with rounded corners, using a style object.
Make a Button that gets the class btn, plus btn-primary when primary is true and btn-disabled when disabled is true.
Trade-offs
- ↔
Inline styles are easy to compute from data and can't leak to other elements, but they can't express hover, media queries or animations, and they bloat the HTML. Classes are the better default; Phase 11 compares CSS Modules, Tailwind and CSS-in-JS.
- ↔
Hand-written class joining is free;
clsxcosts a tiny dependency but reads better when there are many conditions.
Done when you can
I can write a style object with camelCase properties.
I know which numbers become
pxand which stay plain.I can set a CSS custom property from React.
I can add and remove classes based on data.
I can choose between a class and an inline style.