Jay Gould

React styling, CSS and components... the React way

March 30, 2017

React

Over the last 2 years or so I’ve been developing some apps and websites using Angular and Angular 2, such as experimenting with a recipe app as shown in [this post]({{ site.url }}{%post_url 2016-11-31-app-development-ionic-framework%}). As I wanted to level up in Angular 2 over React, I’ve never looked into React more than playing with the initial Hello World, but a recent turn of events at work has lead me into doing some React dev work.

When learning something new like this I find I forget what initially stumps me and leaves me racking my brain for a solution. You eventually learn the framework efficiently enough to use it day-to-day, and the initial problems or questions you have simply get forgotten. So I thought I’d write a post on React at the time I’m jumping into it, and explaining my initial thoughts for anyone else going through the same problems I did.

The first week I concentrated mainly on styling, because believe me, it’s not as easy as you may think.

If you haven’t done already, I’d recommend installing create-react-app via npm:

npm install -g create-react-app
create-react-app my-app
cd hello-world
npm my-app

This takes away a lot of the complications with installing React and configuring Webpack.

Don’t use your own CSS files in the index page

So let’s start real basic - most normal websites will have scripts and CSS files included in the head/foot of the website using tags such as like below:

<link rel="stylesheet" type="text/css" href="style.css" />
<script src="script.js"></script>

Frameworks such as React, Ember and Angular use build tools to bundle the many JS and CSS fils together for performance reasons. React and Angular both use Webpack for this by default, which is amazing by the way, so have a play with Webpack regardless of whether you’re using React or not!

React uses Webpack to go through the /src folder in your app and grab any references to CSS in your code to bundle. This leads to the first consideration with React - don’t use custom made global CSS file in the header of the app. You must let Webpack do it’s thing to save a lot of confusion. This may seem obvious, but you’ll understand why I mention this when you begin using React.

Styling belongs to components

Well… kind of. Another thing React and A2 have in common is that they are heavily promoting the use of components. The idea behind this is that everything in an application should be self-contained so it’s re-usable and easily testable. You may have a component for a login box, a footer, a header, and a sidebar for example. One of the advantages of this is you’re able to add styling directly to these components, which is great news for larger applications as it keeps things organized.

There are a few ways to style components so I’ll cover a really basic example of 2 of them.

  • CSS import

This is the most basic way of styling a component, and is the default setup when installing create-react-app:

import React, { Component } from "react"
import "./Header.css"

class Header extends Component {
  render() {
    return (
      <div className="header">
        <div className="headerInner">
          <h2>Welcome to React</h2>
        </div>
      </div>
    )
  }
}

export default Header

A quick side note - React uses JSX to render the HTML code. As “class” is a reserved keyword in JS, the HTML class must be called “className”.

The Header.css file is imported to the component which means Webpack will eventually bundle this shit together with everything else. By default in create-react-app when the app is compiled these styles will still be global in the sense that you’ll be polluting the global namespace, but it’s a hell of a lot easier to work with as opposed to one huge CSS sheet as the files are separate, kind of how you may normally use SASS sheets.

  • CSS in JS

I’ve seen this way used in a lot of tutorials around the web. I think at one stage it was “the” way to style React components (I could be wrong), but nowadays I don’t think it’s got as much traction. Here’s an example:

import React, { Component } from "react"
import logo from "./../../assets/logo.svg"
//imported style
import importedStyle from "./header.js"

class Header extends Component {
  render() {
    //inline style
    const inlineStyle = {
      borderTop: "4px solid rgb(98, 201, 73)",
    }
    return (
      <div style={importedStyle}>
        <img src={logo} style={inlineStyle} alt="logo" />
        <h1>Header</h1>
      </div>
    )
  }
}

export default Header

You can see above I’ve shown 2 examples of using CSS in JS - one which is imported and one which is styled inline.

The main benefit of CSS in JS is that it will locally scope your styles to your component. This means you can call an element .logo in the header, and have another element in the footer also called .logo and the styles will not affect each other. It does this by naming each of the classes something different, so the one in the header may be .headerlogon343j and the one in the footer .headerlogog45d8 (for example).

This is handy as you don’t have to worry about the naming of classes - everything can be named really simple. There are a load of other reasons why local scoping of CSS is great, so give it a Google to find out more. Another benefit is that it’s good for editing CSS values dynamically based on your application state.

However, the major downfalls are that you can’t use media queries, psuedo classes, or SASS which is a major negative for me.

  • CSS modules

If you don’t already know, CSS Modules are a way of locally scoping your CSS to your component, similar to the CSS in JS way above. However the major difference is that with CSS modules the CSS can stay in it’s own file like normal CSS:

import React, { Component } from "react"
import logo from "./../../assets/logo.svg"
import styles from "./header.css"

class Header extends Component {
  render() {
    return (
      <div className={styles.appHeader}>
        <img src={logo} className={styles.appLogo} alt="logo" />
        <h1>Home</h1>
      </div>
    )
  }
}
export default Header

This is my preferred way by far. Instead of styling using the style={style} syntax like the CSS in JS option, CSS modules work by adding a JS object to the className property, all done through Webpack.

To read more around CSS modules, see this CSS Tricks article. It goes into great detail and covers how to install using react from the ground up (not using create-react-app). It took me a good hour to get working in my React app because I was Googling the wrong thing. Make sure you specify “create-react-app” in your Google searches if you wish to find specific information about the original create-react-app setup.

For example, create-react-app doesn’t support CSS Modules by default. You have to eject the app first, meaning all of the config and supplemental files for the create-react-app are visible. Warning: there’s no going back when you’ve done this:

npm run eject

Then you have to edit the webpack.config.dev.js file to enable CSS modules. See mine below around line 140-150 ish:

{
  test: /\.css$/,
  loader: `style!css?importLoaders=1&modules&localIdentName=[name]__[local]___[hash:base64:5]!postcss`
}

SASS is not enabled by default

Oh yeah and another thing!

SASS/SCSS is not enabled by default. I have no idea why but it took me a while to figure out how this all fits in with CSS modules or even the entire application. I guess at such a granular level of styling small components, you may not get the full benefit of SASS? I don’t know.

The answer I have is to edit the Webpack config file and add the following loader options:

{
  test: /\.scss$/,
  loader: combineLoaders([
    {
      loader: 'style-loader'
    }, {
      loader: 'css-loader',
      query: {
        modules: true,
        localIdentName: '[name]__[local]___[hash:base64:5]'
      }
    }, {
      loader: 'sass-loader'
    }
  ])
}

Global styles are a mind-f**k

You could argue that if you’re really good at writing CSS, you won’t have much need for CSS modules or localizing your styling to a component and “writing global CSS is easy”, but I think CSS modules helps a great deal whether you’re shit hot or not.

At some point though when using CSS modules, you’ll want to have some CSS which is global. Think of all the CSS resets you normally do, or site-wide padding classes, styling all the p,span,h1,h2 etc… This is another complication to deal with. At this point I’d like to say that although React is seen to have a bit more of an easy learning curve compared to Angular, styling in Angular is much easier IMO. Or perhaps not easier, maybe it feels easier because Angular and Angular 2 both have “the Angular way” of doing everything, but React doesn’t. Or at least it doesn’t have an official “way” which is promoted by the creators of the platform.

Anyway back to global styles. There are many ways to style globally if you’re using BEM or the basic CSS import outlined above, but I’ll go through styling globally using CSS modules as that’s my setup.

  • Global psuedo class

By design, CSS modules locally scope CSS to a component, so to turn the CSS in your file from .headerlogo3jgg6 to .header.logo, you need to do the following:

:global {
  .header.logo {
    ...;
  }
}

Adding this global psuedo class will allow this CSS property to be used by the entire application. This then means when using the class, you need to add the classes to your HTML the normal way, for example:

<img class="logo" src="mylogo.png" />

When you’ve committed to CSS modules, this is kind of the only “proper” way to opt out of the localised styling (unless you edit your Webpack config file).

It’s also worth noting that it seems weird to have global styling (such as .btn) in a login form component. What if you want to access the styling for a button in another part of the application? Which you pretty much definitely will. For this reason, I have found it great to put your global styles in your root component (your app.css from the create-react-app original setup). Just makes sense and keeps things tidy, plus if you’ve used SASS you can nest a whole sheet in a global psuedo class if you like. Sweet!

  • Compose!

Finally, one great way of handling global styling is the use of the composes property. This is similar to the @extends property with SASS. You can have one element extend the properties of another, from the same stylesheet or another style sheet:

//header.scss
.appHeader {
  composes: sitePadding from "global/global.scss";
}

//global.scss
.sitePadding {
  padding: 0px 20px;
}

Thanks for reading

That about sums up my thoughts and experience with React. I think it’s good and I can see why it may be easier to get into than Angular, but I prefer the convention over configuration with Angular 2.

This has only scratched the surface with React. There’s much more to get stuck into with passing data around between components, routing, server side React, testing etc, but I’ll go through these in another post. From my initial playing around in the last couple of weeks though the rest of it isn’t as confusing as styling!


Senior Engineer at Haven

© Jay Gould 2023, Built with love and tequila.