Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~19 min· topic 5 of 7

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 style attribute.
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.5 or zIndex: 2.
CSS custom property
A CSS variable such as --accent, read with var(--accent).
Conditional class
A class name added or removed depending on data, like done on 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.

Task.jsxwhole filejsx
// 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.

Task.jsxwhole filejsx
<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.

cx.jswhole filejavascript
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.

Bar.jsxwhole filejsx
<div style={{ width: progress * 3, backgroundColor: "#2f9e44" }} />
// becomes: style="width: 210px; background-color: rgb(47, 158, 68);"
Add an inline style for a computed valuediagram
Rendering diagram…

Try it yourself

  1. 1

    Change the unit

    In the progress bar, change width: progress * 3 to width: progress + "%". Predict the second log line. (width: 70%;: a string is used exactly as written.)

  2. 2

    Add a class

    Give Task a today prop and add today && "today" to the cx call, with a CSS rule .today { background: #fff9db; }. Render <Task title="Call Gran" today />.

  3. 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 reads var(--accent).

Code & diagrams

Style objects: camelCase keys, numbers become px New tab

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

Press Run to see the page.

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);
Conditional class names, two ways New tab

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

Press Run to see the page.

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".

terminal
$ Console
── what you'll see ──
Uncaught Error: The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.
An error occurred in the <p> component.

Break #2

Keep the CSS dash

In barStyle, change backgroundColor: to "background-color":.

terminal
$ Console
── what you'll see ──
Unsupported style property background-color. Did you mean backgroundColor?

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 (isUnitlessNumber in react-dom) to decide when to add px. Custom properties (names starting with --) are set with style.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 !important in values; if you truly need it, use a class.

Remember this

  1. 1

    Class names are the main way to style React apps. Write CSS rules in a stylesheet (.card { … }) and put className="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 /css course teaches CSS itself.

  2. 2

    The **style attribute 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's element.style API: background-color becomes backgroundColor, font-size becomes fontSize, z-index becomes zIndex. Values are strings ("2px solid red") or numbers.

  3. 3

    Numbers become pixels. For properties that need a length, React adds px to 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, order and a few others. For any other unit, write a string: width: "50%", margin: "1rem". A string number with no unit, like marginTop: "10", is invalid CSS and the browser silently ignores it.

  4. 4

    CSS custom properties (variables) keep their exact name in quotes: style={{ "--accent": "#087ea4" }}, used in CSS as var(--accent). This is a neat way to pass one value from React into a whole stylesheet without inline-styling every element.

  5. 5

    Conditional class names: className is 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 as clsx and classnames do exactly this with an object syntax: clsx("task", { done, urgent })`.

  6. 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

01

How is the style attribute in JSX different from HTML's?

02

When does React add px to a number in a style object?

03

Show two ways to add a class only when a condition is true.

04

When would you choose an inline style over a class?

Practice

01

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.

02

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; clsx costs 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 px and 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.