styled-components, the Modern Way to Handle CSS in React

Flavio Copes

Working with React you have a lot of choice for when it comes to handling styling using CSS-in-JS. You can learn about a lot of the available options in our CSS-in-JS Roundup.

Most libraries have a lifecycle. They rise in popularity and then they get superseded by a better solution.

One of the libraries at its popularity peak is 💅 styled-components.

Easy to Get Started

The creator of styled-components is also the maintainer of react-boilerplate, one of the most popular ways to set up a React project.

The boilerplate includes styled-components and it makes perfect sense to just use the boilerplate if you’re starting a new app from scratch.

To get started, clone the repo:

$ git clone --depth=1 https://github.com/react-boilerplate/react-boilerplate.git

…and then cd into into it and run npm run setup.

The boilerplate provides an example app which is very convenient to start diving into styled-components.

Jump start it with npm start, and reach your app at http://localhost:3000.

The react boilerplate default view

The components in the example app are already using styled-components. See app/containers/App/index.js for an example:

app/containers/App/index.js

// ...other imports
import styled from 'styled-components';

const AppWrapper = styled.div`
  max-width: calc(768px + 16px * 2);
  /* ... */
`;

export default function App() {
  return (
    <AppWrapper>
      {/* ... */}
    </AppWrapper>
  );
}

This is the Styled Component associated to the AppWrapper container, responsible for rendering the page wrapper. The outputted DOM will be a div element with the style applied.

The boilerplate uses hot reloading, so you can tweak something, save the file, and the changes apply to the page.

Try setting a custom max-width to 500px:

const AppWrapper = styled.div`
  max-width: 500px;
  /* ... */
`;

and save the file:

The home page with our change

You just edited your first Styled Component! 🎉

Forget About Classes

As you can see, there is nothing that links the style you just edited to its container. There is no className, which you would have used in CSS to link a style to an element.

The usual workflow when building a web interface with CSS is:

  1. You create an HTML structure, with unique classes or id attributes
  2. You target elements in the page by using class or id selectors in CSS

This requires to keep those in sync, in case you need to change them. It also requires you to research a naming structure that can accomodate all your elements.

If you’re in a team, this usually means having naming conventions which might be hard to enforce. Not when laying out the initial structure of the project, but easy to bypass when it comes to making quick fixes. styled-components create classes on the fly for you, with unique class names for all your elements.

This guarantees that no style can leak out to other elements, like it could happen with reusing class names across the page.

It’s Just CSS

Some of the existing CSS-in-JS libraries let you write CSS in JavaScript in the form of JavaScript objects. This requires some cognitive load and it’s a barrier to entry for many designers that know CSS but not JavaScript.

styled-components rely on JavaScript template literals to let you write actual CSS, which can be simply copy-pasted from your CSS files.

The only thing to note is that media queries use a “special syntax”, where you omit the selector, instead of:

@media (max-width: 700px) {
 .app-wrapper {
    background: white;
 }
}

you write:

const AppWrapper = styled.div`
  /* ... */
  @media (max-width: 700px) {
    background: white;
  }
`;

It Makes CSS Easier and Better

styled-components are “just CSS”, but a slightly enhanced CSS.

It allows CSS nesting, one of the main conveniences of common CSS preprocessors. Let’s give a quick test, by flipping any image in the page:

const AppWrapper = styled.div`
  max-width: calc(768px + 16px * 2);
  /* ... */

  img {
    transform: scaleX(-1);
  }
`;

Images flipped in the example

It also handles vendor prefixes for you using inline-style-prefixer. In the example above, the use of transform adds these vendor prefixes to the generated CSS:

.fpcXGq img {
  -webkit-transform: scaleX(-1);
      -ms-transform: scaleX(-1);
          transform: scaleX(-1);
}

Customize the Components

If you want to make the right button grey instead of blue, it’s easy to overwrite this specific CSS property. The buttons are two instances of HeaderLink, which is a Link component from react-router-dom with some styles applied:

/app/components/Header/HeaderLink.js

import { Link } from 'react-router-dom';
import styled from 'styled-components';

export default styled(Link)`
  /* ... */
  border: 2px solid #41ADDD;
  color: #41ADDD;

  /* ... */
`;

Now, if you want to create a gray button it’s pretty easy:

/app/components/Header/GrayHeaderLink.js

import styled from 'styled-components';
import HeaderLink from './HeaderLink';

const GrayHeaderLink = styled(HeaderLink)`
  color: darkgray;
  border: 2px solid darkgray;
`;

and now use this component in your JSX, from:

<NavBar>
 <HeaderLink to="/">
   {/* ...children */}
 </HeaderLink>

 <HeaderLink to="/features">
   {/* ...children */}
 </HeaderLink>
</NavBar>

to:

<NavBar>
 <GrayHeaderLink to="/">
   {/* ...children */}
 </GrayHeaderLink>

 <GrayHeaderLink to="/features">
   {/* ...children */}
 </GrayHeaderLink>
</NavBar>

This approach works great when you don’t own your components. In this case the Link came from the react-router-dom package and we had no control over it.

Otherwise it’s even simpler. This is the default style of a button:

app/components/Button/buttonStyles.js

import { css } from 'styled-components';

const buttonStyles = css`
  /* ... */
  border: 2px solid #41addd;
  color: #41addd;

  /* ... */
`;

export default buttonStyles;

You'll notice the use of the css helper, which allows the use of interpolations inside your CSS rules.

Inserting a simple prop into the template literal will allow us to have a different style in a component by selecting the color based on the prop value:

const buttonStyles = css`
  /* ... */

  border: 2px solid ${(props) => props.gray ? 'darkgray' : '#41addd'};
  color: ${(props) => props.gray ? 'darkgray' : '#41addd'};

  /* ... */
`;

The StyledButton component is then exported using a syntax like the following:

/app/components/Button/StyledButton.js

import styled from 'styled-components';

import buttonStyles from './buttonStyles';

const StyledButton = styled.button`${buttonStyles}`;

export default StyledButton;

Now you can make the button grey by just writing:

<StyledButton gray />

Learn More

This is the tip of the iceberg. styled-components allow you to perform much more advanced configurations.

Learn all styled-components can provide in the official documentation.


* Note that the code snippets in this post taken from the React Boilerplate project are licensed under MIT and © 2017 Maximilian Stoiber. You can find a copy of the license here.

  Tweet It

🕵 Search Results

🔎 Searching...