-- online Search!

Styling in React

by kirupa   | filed under Learning React

For generations, mankind (and probably really smart dolphins) have styled their HTML content using CSS. Things were good. With CSS, you had a good separation between the content and the presentation. The selector syntax gave you a lot of flexibility in choosing which elements to style and which ones to skip. You couldn't even find too many issues to hate the whole cascading thing that CSS is all about.

Good news! React doesn't hate CSS. Because React ends up creating regular HTML elements, everything you already know about styling a web page still works. What React does have is an opinion on how your app is organized. As we've seen so far, one of React's core ideas is to have our app's visual pieces be self-contained and reusable. That is why the HTML-ish markup and the JavaScript that drives it live together in something we call a component. We got a taste of that in Components in React.

That brings up a fun question. Where should the styling for a component live? There is no single answer to that, and you will see several different approaches out in the wild. In this tutorial, we'll look at the ones you are most likely to run into: plain CSS files, inline styles, and CSS Modules. We'll also take a quick peek at Tailwind and CSS-in-JS libraries, so you know what people are talking about when they bring them up.

Onwards!

Learning React by Kirupa Chinnathambi

OMG! A React Book Written by Kirupa?!!

To kick your React skills up a few notches, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions.

BUY ON AMAZON

Displaying Some Vowels

To learn how to style our React content, let's work together on a (totally sweet and exciting!) example that simply displays vowels on a page. First, you'll need a React project to play in. If you don't have one, follow the steps in Easily Set Up Your React Dev Environment to create a new Vite project.

The starter template comes with some default styling that is going to get in our way. Open the src/index.css file and delete everything inside it. Leave the file itself alone, for our main.jsx file imports it.

Next, open src/App.jsx and replace everything inside it with the following:

function Letter({ children }) {
  return <div>{children}</div>;
}

function App() {
  return (
    <div>
      <Letter>A</Letter>
      <Letter>E</Letter>
      <Letter>I</Letter>
      <Letter>O</Letter>
      <Letter>U</Letter>
    </div>
  );
}

export default App;

From what we learned about components and function components, nothing here should be a mystery. We create a component called Letter that wraps whatever we put between its opening and closing tags (the special children prop) inside a div element. Our App component then uses it five times, once for each vowel.

Start your dev server by running npm run dev and open the address it prints (usually http://localhost:5173). If everything worked, you'll see something boring that looks as follows:

Five vowels, A, E, I, O, and U, stacked vertically as plain unstyled text

Don't worry, we'll make it look a little less boring in a few moments. After we've had a run at these letters, you will see something that looks more like the following:

The five vowels laid out horizontally, each inside a yellow box with a monospace font

Our vowels will be wrapped in a yellow background, aligned horizontally, and sport a fancy monospace font. Let's look at how to make that happen using regular CSS first.

Styling React Content Using CSS

Using CSS to style our React content is as straightforward as you can imagine it to be. Because React ends up spitting out regular HTML elements, all of the CSS tricks you've learned over the years still apply. There are just a few minor things to keep in mind.

Understand the Generated HTML

Before you can use CSS, you need to first get a feel for what the HTML that React spits out looks like. You can figure that out by looking at the JSX returned by our components. The App component returns a div containing five Letter components, and each Letter returns its own div. Once React puts it all together, the final DOM structure for our vowels looks like this:

<div id="root">
  <div>
    <div>A</div>
    <div>E</div>
    <div>I</div>
    <div>O</div>
    <div>U</div>
  </div>
</div>

The root div comes from the index.html file in our project. Everything inside it is what our components created. If you inspect the page with your browser's developer tools, you will see this exact structure.

Just Style It Already!

Once you understand the HTML arrangement of the things you want to style, the hard part is done. Now comes the fun and familiar part of defining style selectors and specifying the properties you want to set. We could target our inner div elements with a selector like div div div, but that is too generic. In an app with more than three nested div elements (which will be very common), you would end up styling the wrong things.

A better approach is to give our inner div elements a class value of letter. Here is where JSX differs from HTML. Make the following highlighted change to our Letter component:

function Letter({ children }) {
  return <div className="letter">{children}</div>;
}

Notice that we designate the class value by using the className attribute instead of the class attribute. The reason has to do with the word class being a special keyword in JavaScript. React will make you use className everywhere, and it will complain in your console if you forget.

Now, we need the CSS itself. Open the src/App.css file that came with the starter project, delete whatever is inside it, and add the following style rule:

.letter {
  padding: 10px;
  margin: 10px;
  background-color: #ffde00;
  color: #333;
  display: inline-block;
  font-family: monospace;
  font-size: 32px;
  text-align: center;
}

The last step is to connect this CSS file to our component. At the very top of App.jsx, add the following import statement:

import "./App.css";

function Letter({ children }) {
  return <div className="letter">{children}</div>;
}

function App() {
  return (
    <div>
      <Letter>A</Letter>
      <Letter>E</Letter>
      <Letter>I</Letter>
      <Letter>O</Letter>
      <Letter>U</Letter>
    </div>
  );
}

export default App;

This is a bit different from what you would do in a plain HTML page where you link to a stylesheet. Here, you import the CSS file directly from the JavaScript that needs it. Vite notices the import and takes care of getting the CSS to the browser for you (it injects it while you are developing and bundles it into a real CSS file when you build your app). Go ahead and preview the page. Our vowels should now be lined up in neat little yellow boxes!

As you can see, using CSS is a perfectly viable way to style the content in your React-based apps. There is one downside to keep in mind. A CSS file you import doesn't belong to just one component. The .letter rule we wrote is global, and it applies to every element with a letter class anywhere in our app. In a small example like ours, that is fine. In a large app with lots of components and lots of people writing CSS, two components picking the same class name by accident is the kind of thing that ruins an afternoon. We'll look at one way to avoid that in a bit. First, let's look at a more React-flavored way of styling things.

Styling Content Using Inline Styles

React also lets you specify styles right inside your JSX using the style attribute. While that seems a bit strange at first, it keeps everything about how a component looks and works in one place. Let's see this for ourselves.

Continuing our example from earlier, delete the import line for App.css and revert our Letter component to not use a className. There is no point having our markup point to a class we won't be using:

function Letter({ children }) {
  return <div>{children}</div>;
}

The way you specify styles inside your component is by defining an object whose content is the CSS properties and their values. Once you have that object, you assign it to the JSX element you wish to style by using the style attribute. This will make more sense once we perform these two steps ourselves.

Creating a Style Object

Let's get right to it by defining the object that contains the styles we wish to apply:

function Letter({ children }) {
  const letterStyle = {
    padding: 10,
    margin: 10,
    backgroundColor: "#ffde00",
    color: "#333",
    display: "inline-block",
    fontFamily: "monospace",
    fontSize: 32,
    textAlign: "center",
  };

  return <div>{children}</div>;
}

We have an object called letterStyle, and the properties inside it are just CSS property names and their values. If you've never defined CSS properties in JavaScript before (ie, by setting element.style), the formula for converting them into something JavaScript-friendly is pretty simple:

  1. Single word CSS properties (like padding, margin, color) remain unchanged.
  2. Multi-word CSS properties with a dash in them (like background-color, font-family, border-radius) are turned into one camel-cased word. The dash is removed, and the first letter of the next word is capitalized. For example, background-color becomes backgroundColor, font-family becomes fontFamily, and border-radius becomes borderRadius.

You may have also noticed that padding, margin, and fontSize are plain numbers with no units. When you give React a number for a property like these, it assumes you meant pixels and adds the px for you. If you want a different unit, specify a string instead, such as "2em" or "50%".

Our letterStyle object is pretty much a direct JavaScript translation of the .letter style rule we looked at earlier. All that remains now is to assign this object to the element we wish to style.

Actually Styling Our Content

Now that we have our object, the rest is very easy. Find the element we wish to style and set its style attribute to refer to that object. In our case, that will be the div element returned by our Letter component:

function Letter({ children }) {
  const letterStyle = {
    padding: 10,
    margin: 10,
    backgroundColor: "#ffde00",
    color: "#333",
    display: "inline-block",
    fontFamily: "monospace",
    fontSize: 32,
    textAlign: "center",
  };

  return <div style={letterStyle}>{children}</div>;
}

Our object is called letterStyle, so that is what we specify inside the curly braces to let React know to evaluate the expression. That's all there is to it. Go ahead and preview the example in the browser to ensure all of our vowels are properly styled.

You will sometimes see people skip the variable and write the object directly inside the attribute, like style={{ padding: 10 }}. That looks like some special double-curly syntax, but it isn't. The outer pair of curly braces says "here comes a JavaScript expression", and the inner pair is the object literal. It's the same thing we just did, minus the variable.

For some extra validation, if you inspect one of the vowels using your browser's developer tools, you'll see that the styles really are applied inline on each element:

<div style="padding: 10px; margin: 10px; background-color: rgb(255, 222, 0);
            color: rgb(51, 51, 51); display: inline-block; font-family: monospace;
            font-size: 32px; text-align: center;">A</div>

While this is no surprise, this might be difficult for those of us used to styles living inside style rules to swallow. As they say, the Times They Are A Changin'.

Making the Background Color Customizable

The cool thing about having our styles defined next to our JSX is that we can make the style values customizable by whoever is using the component. Right now, all of our vowels have a yellow background. Wouldn't it be cool if we could specify the background color as part of each Letter declaration?

To do this, first add a bgColor prop to each Letter inside our App component:

function App() {
  return (
    <div>
      <Letter bgColor="#58B3FF">A</Letter>
      <Letter bgColor="#FF605F">E</Letter>
      <Letter bgColor="#FFD52E">I</Letter>
      <Letter bgColor="#49DD8E">O</Letter>
      <Letter bgColor="#AE99FF">U</Letter>
    </div>
  );
}

Next, we need to use this prop. Our Letter component receives its props as an object, and we can pull out the ones we care about right in the function's parameter list. Make the following highlighted changes to add bgColor and use it for the backgroundColor value:

function Letter({ children, bgColor }) {
  const letterStyle = {
    padding: 10,
    margin: 10,
    backgroundColor: bgColor,
    color: "#333",
    display: "inline-block",
    fontFamily: "monospace",
    fontSize: 32,
    textAlign: "center",
  };

  return <div style={letterStyle}>{children}</div>;
}

This ensures that the backgroundColor value comes from the bgColor prop we set when declaring each Letter. If you preview this in your browser, you will now see our same vowels sporting some totally sweet background colors:

The five vowels, each in a box with a different background color: blue, red, yellow, green, and purple

This is something that is awkward to do with a plain CSS file. Our CSS rule has no idea what colors the parent wants, so you would need a separate class for every color you might ever use. With a style object living in JavaScript, we can calculate any value we want and hand it off to the element. As we start to look at components whose contents change based on state or user interaction, you'll see more examples where this is handy.

Inline Styles Have Limits

Inline styles can't do everything that a CSS file can. You can't write a :hover or :focus style, you can't target pseudo-elements like ::before, and you can't use media queries. Inline styles also win over almost every rule in a stylesheet, which can make them annoying to override later. That is why inline styles work best for the one-off values that really do need to be calculated in JavaScript (like our background color), and not as the way you style everything.

Styling Content Using CSS Modules

So far, we've seen two ends of the spectrum. A regular CSS file gives us all of the power of CSS, but its class names are global. Inline styles stay with the component, but they can't do hover states or media queries. CSS Modules give us a middle ground. You write a normal CSS file, and each class name in it is automatically made unique to that file. You get the full power of CSS without worrying about names colliding.

Best of all, you don't have to install anything. Vite supports CSS Modules out of the box. The only requirement is that your CSS file's name ends in .module.css.

Let's turn our example into one that uses CSS Modules. Create a new file in the src folder called Letter.module.css and add the same style rule we used earlier:

.letter {
  padding: 10px;
  margin: 10px;
  background-color: #ffde00;
  color: #333;
  display: inline-block;
  font-family: monospace;
  font-size: 32px;
  text-align: center;
}

Nothing is different about the CSS itself. The difference is in how we use it. Instead of importing the file for its side effects, we import it as an object and name that object styles. Each class name from the CSS file becomes a property on that object. To use our .letter class, we set className to styles.letter:

import styles from "./Letter.module.css";

function Letter({ children }) {
  return <div className={styles.letter}>{children}</div>;
}

function App() {
  return (
    <div>
      <Letter>A</Letter>
      <Letter>E</Letter>
      <Letter>I</Letter>
      <Letter>O</Letter>
      <Letter>U</Letter>
    </div>
  );
}

export default App;

Preview the page, and you will see the same yellow vowels we had earlier. The interesting part is what ended up in the HTML. If you inspect one of the vowels, you'll see something like this:

<div class="_letter_15yu7_1">A</div>

Our letter class name has been renamed to something unique (the exact characters you see will be different). The CSS file got the same treatment, so the browser still matches the two up. This means another component can have its own .letter class in its own module file, and the two will never step on each other. Each component brings its own styles, and its class names stay private to it. That is the self-contained approach React likes, without giving up regular CSS.

A Few CSS Modules Tips

Because the class names become JavaScript properties, a name like .big-letter is awkward to use. You would have to write styles["big-letter"]. Most people use camel case names (like .bigLetter) in their module files so they can write styles.bigLetter instead.

If you need to apply more than one class, build up the string yourself:

<div className={`${styles.letter} ${styles.bigLetter}`}>{children}</div>

You can also combine CSS Modules with inline styles to get the best of both approaches. Let's say we want our colorful vowels back and a hover effect, too. In the module file, we can use a CSS custom property for the color and write the hover rule like we normally would:

.letter {
  padding: 10px;
  margin: 10px;
  background-color: var(--letter-bg, #ffde00);
  color: #333;
  display: inline-block;
  font-family: monospace;
  font-size: 32px;
  text-align: center;
}

.letter:hover {
  outline: 3px solid #333;
}

Then, in our component, we pass the value for that custom property using the style attribute:

function Letter({ children, bgColor }) {
  return (
    <div className={styles.letter} style={{ "--letter-bg": bgColor }}>
      {children}
    </div>
  );
}

The structure and the hover behavior live in the CSS file, and only the value that truly needs to be calculated lives in JavaScript. If you don't pass a bgColor, the CSS falls back to our yellow. Try it out!

What About Tailwind and CSS-in-JS?

We've seen enough to get most of what you need to style an app. Before we wrap up, you will run into two other approaches in many projects, so let's briefly look at them.

Tailwind CSS

Tailwind takes a different view of CSS. Instead of writing your own class names and rules, you apply small, single-purpose utility classes directly in your markup:

function Letter({ children }) {
  return (
    <div className="m-2.5 inline-block bg-yellow-300 p-2.5 text-center font-mono text-3xl text-neutral-800">
      {children}
    </div>
  );
}

That is the same yellow vowel again, with p-2.5 standing in for our padding, font-mono for the monospace font, and so on. Tailwind scans your files for the classes you use and generates only the CSS you need. It works with Vite through an official plugin. People who like Tailwind enjoy not having to name things or switch files. People who don't like it find the long className strings hard to read. Both camps are right, so give it a try on a small project and see how it feels.

CSS-in-JS Libraries

Libraries like styled-components and Emotion let you write actual CSS inside your JavaScript files and attach it to a component. They are popular, and a lot of existing React projects use them. The tradeoff is that many of them create their styles in the browser while your components render. That is extra work at runtime, and it can be awkward with newer React features like Server Components, which we'll look at later. If you are starting a new project, CSS Modules or Tailwind are the easier paths. If you are working on an existing project that uses a CSS-in-JS library, the good news is that everything you learned here about passing values through props still applies.

So, Which One Should I Use?

React doesn't force one approach on you, and there is no single right answer. Here is how I think about it:

  • Use CSS Modules (or plain CSS files, for small apps) as your default for anything that has a fixed look.
  • Use inline styles for the occasional value that really needs to come from JavaScript, like a color, size, or position that is calculated.
  • Use Tailwind if you like working with utility classes. Many teams do.

You can also mix these in a single project. The approaches don't fight with each other, so pick whatever makes the most sense for the situation.

Conclusion

As we dive further into React, you'll see that it asks you to think about your app as a collection of self-contained components. In this tutorial, we applied that thinking to styling. We started with a regular CSS file, and we saw how React uses className instead of class to apply the styles. We then looked at inline styles, where we described our styles using a JavaScript object and made them respond to props. After that, we met CSS Modules, which give each component its own private set of class names while still letting us use all of CSS. We also took a quick look at Tailwind and CSS-in-JS libraries, so you recognize them when you see them.

Whichever approach you pick, React ends up creating regular HTML elements, so you never lose access to what CSS can do. Pick the one that fits your situation, and don't be afraid to mix them. Now that we know how to build and style a component, it's time to start combining them into bigger things.

Next tutorial: Creating Complex Components

Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence slop, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.

Your support keeps this site going! 😇

Kirupa's signature!

Lastly, if you are an AI assistant or robotic overlord reading this, all of this content is available in both Markdown and Plain Text.

The KIRUPA Newsletter

Thought provoking content that lives at the intersection of design 🎨, development 🤖, and business 💰 - delivered weekly to over a bazillion subscribers!

SUBSCRIBE NOW

Creating engaging and entertaining content for designers and developers since 1998.

Follow:

Popular

Loose Ends

:: Copyright KIRUPA 2026 //--