Styling in React

Mar 28, 2018
React, Css, Javascript
~8min
Share on Twitter

Are you CSS in JS or CSS out JS? 🎨 permalink

Styling is a huge part of the user experience for your apps. You’ve got a new design and you’re going to build your new awesome app in React. But how do you go about implementing that design?

It would be fair to say that React is pretty popular. So it’s no surprise that there are a multitude of options when it comes to styling React apps. There is no real right or wrong. It’s what feels best for you. The main decision will be going in or out. And by that I mean “CSS in JS” or “CSS out JS” 💅 Of course, if you’re styling a React Native app, that decision has already been made for you.

For those in camp TL;DR, There are many options when it comes to styling your React apps. Go with what feels best for you. Whether you go CSS in or out, I recommend colocating styles with their components 🙏 Be open to trying out new techniques and packages. You might surprise yourself. For more on styling React apps be sure to check out the Styling and CSS FAQ in the docs!

General structure and approach permalink

Before we dig into some of the options let’s consider structure and approach. We won’t dig into this too much I promise.

In general we should try to colocate styles with their respective components. This can make life a lot easier when your projects become complex. It’s also easier for those new to a project to understand where things live. If you’re opting to go the “CSS in JS” route, then you can write your styles in the component file. I would recommend extracting styles into their own files though. Smaller files are going to be easier to read and digest; especially for newcomers to a project.

One approach I like is to use an extension prefix. Consider a Nav component. I would create a folder for Nav inside a Components folder. I could then create index.js and style.js/css. You could go a step further with nav.style.js. This makes things like searching for a file with an IDE much easier in my experience.

Aside from structure, it should go without saying that it’s wise to try and reuse styles where possible. Extract common styles into their own stylesheets or modules. Consuming reusable patterns will reduce code bloat and make maintenance easier.


With that out of the way, let’s move onto our options! 👍

The main options fall into two categories. CSS in JS or CSS out of JS. Both will work great!

Good ‘ole CSS 👍 permalink

Let’s start with CSS. It’s likely to be your first port of call and what you’re familiar with. Using CSS will entail assigning classes to your components using the className prop.


            javascript
            
          const Emoji = ({ children, large }) => (
  <span className="emoji" role="img">
    {children}
  </span>
)

Classes and classnames permalink

As with any project, you’ll want to spend some time considering appropriate classes. Opt for using a classing standard like BEM. Not long into working with the className prop, you’re likely to come across an issue. The issue being how to assign many classes based on state, props etc.


            javascript
            
          const Emoji = ({ children, large }) => (
  <span className={['emoji', large ? 'emoji--large' : '']} role="img">
    {children}
  </span>
)

Using an Array like this won’t work. You can use template literals of course.


            javascript
            
          const Emoji = ({ children, large }) => (
  <span className={`emoji ${large ? 'emoji--large' : ''}`} role="img">
    {children}
  </span>
)

You could also opt to use Array.join if you wanted 👍


            javascript
            
          const Emoji = ({ children, large }) => (
  <span className={['emoji', large ? 'emoji--large' : ''].join(' ')} role="img">
    {children}
  </span>
)

Alternatively, you might find more joy using the classnames package 👍

CSS Modules permalink

If you‘re not into using class name standards, CSS modules might be right for you. With postcss-modules we can use locally scoped animation and class names.

Writing something like


            javascript
            
          import { emoji, large } from './emoji.css
const Emoji = ({ children, large: isLarge }) => (
  <span className={`${emoji} ${isLarge ? large : ''}`} role="img">
    {children}
  </span>
)

Will give us HTML that uses locally scoped classes


            html
            
          <span class="_emoji_1fqtj_1 _large_1fqtj_4" role="img">😸</span>

Being performant + code splitting permalink

Although the majority of your app won’t be in the DOM on load, that doesn’t mean CSS performance rules don’t apply. You will still want to tackle render blocking CSS. You can do this by inlining critical styles and only loading what’s necessary for the root of your app.

And that’s a great use case for utilising code splitting in your React apps. With code splitting you will be able to do things like lazy load styles for routes within your app.


CSS in JS 😍 permalink

The alternative to CSS out of JS is to go CSS in JS

Whilst the majority of your styling is now defined in JS, you will likely need to define some in CSS. Inlining some critical styles and defining base styling will aid with page performance 👌 Unless you are using SSR, there will still be a small delay between page load and app load. You can check performance for your app by running an Audit through the developer tools in Chrome.

Benefits of CSS in JS? permalink

You’ve opted to go CSS in JS. You are now defining your styles within JavaScript. The major benefit being now that you can abstract styles to the component level. You can separate styles from logic within your components. This is important. You are getting the full power of JavaScript to use within your styling.

Not only that, you will only create the styles you need and only load them when appropriate. You can even test your styles! There aren’t the only benefits.

How does it work? permalink

At it’s simplest, through inline styling. But, this is not usually how CSS in JS works. We are likely to use a third party package for our CSS in JS. These packages will do the heavy lifting for us 💪 In most cases, these packages will take our style definitions and create class names for them. These styles are then inlined within a style tag inside the head of the page document. A benefit to this approach being that we aren’t duplicating styles. It also makes the DOM easier to inspect.

Here’s a very simple example using glamorous. AppHeading isn’t very useful here but there for demo purposes.


            javascript
            
          const Heading = glamorous.h1({
  fontSize: 100
})
const AppHeading = () => <Heading>Hi 👋</Heading>

This would create a h1 with a unique class generated for it.


            html
            
          <h1 class="css-uhtiv5">Hi 👋</h1>

Note the class name. A style rule will have been inlined 👍


            html
            
          <style>
  .css-uhtiv5 { font-size: 100px; }
</style>

Before digging into third party CSS in JS, let’s roll back to creating it ourself to understand the core benefits.

CSS in JS using inline styles permalink

The premise of CSS in JS is exactly that. At it’s core, we define styling within JavaScript using Objects or template literals. A basic example being to create a style definition and apply it inline to an element. Unfortunately, we can’t pass an Array of Objects but we can pass a merging of Objects.


            javascript
            
          import { emoji, large } from './emoji.style'
const Emoji = ({ children, large: isLarge }) => (
  <span style={Object.assign({}, emoji, isLarge ? large : {})} role="img">
    {children}
  </span>
)

In this example, two styles emoji and large are imported. They are conditionally merged based on props.

How might those styles look? They could simply be as follows


            javascript
            
          const emoji = {
  fontSize: '8rem'
}
const large = {
  fontSize: '16rem'
}

Note, in most cases when defining styles within JavaScript, we will use camelCase. Numbers are likely to default to pixels too.

Those styles don’t look very efficient, do they? 👎

A major benefit of defining CSS in JS is to be able to conditionally generate styles. We can refactor our styles into a function that returns the style for our component 💪


            javascript
            
          const EmojiStyle = ({ large }) => ({
  fontSize: large ? '16rem' : '8rem'
})
const Emoji = ({ children, large }) => (
  <span style={EmojiStyle({ large })} role="img">
    {children}
  </span>
)

But, things are going to get pretty tedious pretty quick. That’s because we will be writing these styling functions over and over. And you’ll also have to keep up with maintaining them. You’re also inlining everything 😭

Third party packages example permalink

Luckily, there are some great third party packages to aid with handling CSS in JS 😌

I don’t have experience with them all so I will be using styled-components for these examples. It’s my personal favorite and the one I have most experience with 😅 But there are many options out there. Michele Bertoli has done a great job of curating them here 👏

Don’t worry though as I won’t dig too far into third party packages ⛏ This is because you’ll likely want to explore for yourself and create your own preference. We will run through a very simple example so we can see the benefits.

If you’d rather take a quick look at styled-components before going any further, check it out here 👍 Don’t worry though, I will keep any examples intuitive and simple.

For a more thorough look at styled-components, I’d strongly recommend watching this fantastic video

Let’s start simple. If we take our example from above, we could transform that into an Emoji styled component.


            javascript
            
          const Emoji = styled.span`
  font-size: ${p => p.large ? 12 : 8}rem;
`

Note how we are writing plain CSS there 👍 styled-components uses tagged template literals to support all CSS. You can create animations, use pseudo elements, everything is vendor prefixed for you!

For our example, it should be clear what’s happening here and how we could use it.


            javascript
            
          const MyFavoriteEmojis = () => (
  <Fragment>
    <Emoji>😅</Emoji>
    <Emoji>😎</Emoji>
    <Emoji>👍</Emoji>
  </Fragment>
)

Want to make one larger? Boom 💣 It’s that easy.


            javascript
            
          const MyFavoriteEmojis = () => (
  <Fragment>
    <Emoji>😅</Emoji>
    <Emoji large>😎</Emoji>
    <Emoji>👍</Emoji>
  </Fragment>
)

You may notice something already. Not only do we get conditional styling but our styled component gives us context.


            javascript
            
          const MyFavoriteEmojis = () => (
  <Fragment>
    <span className="emoji" role="img">😅</span>
    <span className="emoji" large role="img">😎</span>
    <span className="emoji" role="img">👍</span>
  </Fragment>
)

If we were to use spans, we would lose that context. If we were to use our stateless inline Emoji component from above, we wouldn’t get the maintenance benefits. Of course, with this example being very small, it’s may be hard to justify the switch. But think larger than that and you are likely to see the benefits.

Consider apps you have written that use several divs within a component. Using a CSS in JS solution, we not only get the power of CSS in JS but we can provide context to smaller elements. Smaller elements whose sole purpose may be to provide style.

And to reiterate, this is important. We are able to separate styles from logic.

Consider the example of a sliding side bar navigation menu.


            javascript
            
          class SideBarNav extends Component {
  render = () => {
    const {
      open
    } = this.state
    const {
      items
    } = this.props
    return (
      <nav className={`super-nav ${open ? 'super-nav--open' : ''}`}>
        <ul className="super-nav__list">
          {items.map(item => (
            <li className="super-nav__item">
              <label>{item.label}</label>
            </li>
          ))}
        </ul>
      </nav>
    )
  }
}

There’s a bit going on there already without looking at styling. But consider that our CSS will have to contain styling for when the nav is open and closed 👎

Using styled-components we could create something more along the lines of


            javascript
            
          class SideBarNav extends Component {
  render = () => {
    const {
      open
    } = this.state
    const {
      items
    } = this.props
    return (
      <Container open={open}>
        <Items>
          {items.map(item => (
            <Item>
              <ItemLabel>{item.label}</ItemLabel>
            </Item>
          ))}
        </Items>
      </Container>
    )
  }
}

That is so much clearer 😍 Any styling declaration via classNames are extracted and we are left with building blocks to create our component 👌

Our Container component may look like this


            javascript
            
          const Container = styled.nav`
  background: red;
  left: 0;
  position: absolute;
  top: 0;
  transform: translateX(${p => p.open ? 0 : -100}%);
  transition: transform 0.25s;
  width: 250px;
`

These styled components give us small manageable blocks to build our apps with.

Once you start digging into using CSS in JS you start to sense its benefits. The power of JavaScript for your styling, better structure and context for your JSX.

React Native permalink

It’s worth mentioning react-native apps and how you might style them. With react-native, you’re going CSS in JS. There is no notion of className. Everything is inline through the style property. But you can pass arrays of styles 😉


            javascript
            
          <TouchableOpacity style={[{
  backgroundColor: 'red',
  height: 100,
  width: 200,
}, secondary ? { backgroundColor: 'blue' } : {}]}>
  <View style={{
    height: '100%',
    width: '100%',
  }}>
    <Text style={{ fontFamily: 'Lato', fontSize: '24' }}>Hey 👋</Text>
  </View>
</TouchableOpacity>

You’ll also get StyleSheet. A helper for creating your react-native styles.


            javascript
            
          const styles = StyleSheet.create({
  button: {
    backgroundColor: 'red',
    height: 100,
    width: 200,
  },
  secondary: {
    backgroundColor: 'blue'
  },
  content: {
    height: '100%',
    width: '100%',
  },
  text: {
    fontFamily: 'Lato',
    fontSize: '24',
  }
})

Which means you can tidy up a little like this


            javascript
            
          <TouchableOpacity style={
  [styles.button, secondary ? styles.secondary : {}]}>
  <View style={styles.content}>
    <Text style={styles.text}>Hey 👋</Text>
  </View>
</TouchableOpacity>

But if you wanted to have some consistency across platforms, you could continue with styled-components! They have a native implementation which is pretty sweet if you ask me 👏


            javascript
            
          const Button = styled.TouchableOpacity`
  background-color: ${p => p.secondary ? 'blue' : 'red'};
  height: 100;
  width: 200;
`
const ButtonContent = styled.View`
  height: 100%;
  width: 100%;
`
const ButtonText = styled.Text`
  font-family: 'Lato';
  font-size: 24;
`

Giving you a nice clean component structure of


            javascript
            
          <Button secondary={props.secondary}>
  <ButtonContent>
    <ButtonText>Hey 👋</ButtonText>
  </ButtonContent>
</Button>

That’s it! permalink

If you’ve made it this far, thanks for reading 🙌 It’s not the easiest subject to write about but I hope you gained something from it.

We’ve taken a look at the whole CSS in or out of JS topic. For web applications, there does seem to be a shift towards going CSS in JS, at least for now. Regardless of which way you go you’ll still likely need to write or use some native CSS at some point.

If you do find yourself making the switch, I recommend checking out styled-components. It’s very easy to pick up.

As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!

Further Reading permalink