5 Ways To Style React Components

April 1, 2018

The chaos (or inventiveness) of the javascript ecosystem is reflected in all the choice you have to style React components.

In this post I'll discuss some of the approaches you can take to style React components.

From the 2016 StateOfJs survey, we learned:

Looking at the result of the survey, it seems both SASS and Plain CSS are used by developers at the same level. But looking at the satisfaction rate, it turns out that developers who use SASS and CSS Modules are more satisfied with them compared to the other options.
Although it might seem like Plain CSS comes out on top, we find something interesting when we look at the correlation values of the heatmap.
According to the chart, there's a strong correlation between using plain CSS and not using a JavaScript framework for your client-side code; and conversely, using SASS means you're more likely to also use a front-end frameworks.

Using Inline Styles

This is the default CSS-in-js approach that is baked into React. You pass an object with camelcased styles to your React component:

<div styles={{ color: "red" }}>red</div>

This approach fits with the modularity of components. Let's say you have a button.js component. If you're only using inline styles then all your styling will be found in one place (or close by).

Example

const styles = {
  backgroundColor: "#f8f8f8",
  border: "1px solid #dd",
  padding: "8px 16px"
};
const Btn = () => (
  <button style={styles}>Click me!</button>
)

Advantages:

  • if you want to build portable React component that can be used in any React app, CSS-in-js is almost mandatory
  • convenience of having style and component logic consolidated in one place
  • keeps all the style logic in javascript rather than pulling it out into SASS
  • makes it easy to change styles based on component state

Disadvantages

  • commingled style and logic
  • code duplication

The main reason I don't use this approach is because I prefer to write plain ole' css and it results in a lot of duplicated styling.

An External Stylesheet

You can also import a regular stylesheet.

If you're using Webpack, you can include the css file in a React container component by installing style-loader and css-loader:

npm i style-loader css-loader --save-dev

Next add this to the loaders section of your Webpack config file:

module: {
  rules: [{
    test: /\.css$/,
    use: [
      'style-loader',
      'css-loader'
    ]
  }]
}

Finally require the css in the entry point to your app:

import './style.css';

Advantages:

  • Write regular css
  • Separation of style and content
  • Maintain modularity if you create a separate css file for each component, e.g., in components/Btn you have Btn.js, Btn.css, and so forth.

Disadvantages

  • Can't control styles based on component state without also passing style prop
  • Requires webpack, css-loader, style-loader

Styled-Components

Styled components is pretty nifty. To get started:

npm i styled-components --save-dev

And here's how you use it.

Example

import React from 'react';
import styled from 'styled-components';
const Btn = styled.button`
  background-color: #f8f8f8;
  border: 1px solid #dd;
  padding: 8px 16px;
`;
class App extends React.Component {
  render() {
    return(
      <div>
        <Btn />
      </div>
    );
  }
}

Styled components lets you write traditional css write in your js files. You keep the style logic in javascript but still write conventional css (background-color: #f9f9f9 instead of { backgroundColor: '#f9f9f9' }).

Styled-components also makes it easer to import default styles and then modify them. This cuts down on the style duplication the traditional inline styles approach is vulnerable to.

You can pass props with styled-components to handle logic:

const Button = styled.button`
  /* If it's a small button use less padding */
  padding: ${props => props.small ? '0.25em 1em' : '0.5em 2em'};
  /* …more styles here… */
`;
const App = () => (
  <Button small={true}>
)

And manipulate styles based on device:

import { css, styled } from 'styled-components'
export const media = {
  handheld: (...args) => css`
    @media (max-width: 420px) {
      ${ css(...args) }
    }
  `
}
// Make the text smaller on handheld devices
const Box = styled.div`
  font-size: 16px;
  ${ media.handheld`
    font-size: 14px;
  ` }
`;

Aphrodite

Aphrodite is a clean way to write CSS in JavaScript and embed styles in individual UI components.

Example

import React from 'react';
import { StyleSheet, css } from 'aphrodite';
const styles = StyleSheet.create({
  red: {
    backgroundColor: 'red'
  }
});
const App = () => (
  <span className={css(styles.red)}>
    This is red.
  </span>
)

Features

  • Works with and without React
  • Supports media queries
  • Supports pseudo-selectors like :hover, :active, etc.
  • state in components. :visited works just fine too.
  • Supports automatic global @font-face detection and insertion.
  • Respects precedence order when specifying multiple styles
  • Injects only the exact styles needed for the render into the DOM.
  • Can be used for server rendering
  • Small runtime (20k, 6k gzipped)
  • No external CSS file generated for inclusion
  • Autoprefixes styles

Styled-Jsx

I don't think this is the best option, but I've used styled-jsx along with nextjs to style React components.

Example

const RedText = () => (
  <div>
    <p>only this paragraph will get the style :)</p>
    { /* you can include <Component />s here that include
         other <p>s that don't get unexpected styles! */ }
    <style jsx>{`
      p {
        color: red;
      }
    `}</style>
  </div>
)

Features

  • Full CSS support, no tradeoffs in power
  • Runtime size of just 2kb (gzipped, from 6kb)
  • Complete isolation: Selectors, animations, keyframes
  • Built-in CSS vendor prefixing
  • Very fast, minimal and efficient transpilation (see below)
  • High-performance runtime-CSS-injection when not server-rendering
  • Future-proof: Equivalent to server-renderable "Shadow CSS"