• Portretfoto van Thijs Kramer
    Thijs Kramer

Styled Components: a brief introduction

Styling webpages can be done in numerous ways. I'd like to show you a few.

For ages webpages have been split up into markup (HTML), styling (CSS) and logic (Javascript). Since frameworks like React emerged people started to think differently about this approach. The split between logic, styles and markup started to be questioned, and therefore new best practices and patterns are emerging from the smoking ruins that used to be comfortable certainties.

traditional styling

The traditional way of styling is to add some ids and classes to your markup, add some rules to your stylesheet, and keep your fingers crossed. In CSS everything is global. So as your project grows, these stylesheets explode and you end up with selectors like #content > .container nav ul li a.selected. And if this selector exists in another stylesheet that was loaded earlier, you'll need an occasional !important to 'win' this selector battle. This approach is good enough for small projects, but when projects start to grow, you want to keep things more maintainable.

CSS architecture

That's why people invented CSS methodologies like BEM (Block Element Modifier) or SMACSS (Scalable and Modular Approach for CSS). While these methodologies have downsides like a complex naming scheme (classnames like nav__button--active), they at least provide some structure to a project.

Pre- or postprocessors

CSS lacks many features that would come in handy while developing. To mention a few: variables, nesting, color functions, or the fact that writing CSS quickly becomes repetitive. CSS preprocessors like SASS, LESS or Stylus try to fill in this gap. They process the authored code into valid CSS code that browsers understand. A postprocessor like Autoprefixer even prefixes CSS properties that need a vendor prefix.

React based approaches

Together with React, other alternatives for styling emerged. From now on it's possible to write CSS that is more maintainable, modular, scalable and scoped to specific elements. This can be achieved in numerous ways, which I'll show you a few of:

Inline styles

In ancient times we could write our styles inline. That was always condemned as wrong: styles should live in a separate file. But that's not the case anymore. So instead of including a CSS file and writing this:

render() {
  return (
    <ul class="todos">
      {items.map(item => <li>{item}</li>)}
    </ul>
  );
}

we could write this:

render() {
  const styles = {
    margin: '0 0.5em',
    listStyle: 'none',
  };

  return (
    <ul style={styles}>
      {items.map(item => <li>{item}</li>)}
    </ul>
  );
}

In earlier times we would add or remove a CSS class name from the element to alter the style bases on logic, for example to indicate if a menu item is currently active. One of the benefits of styling at component level is that it is easier to alter styles based on logic:

render() {
  const { active } = this.props;
  const styles = {
    textDecoration: active ? 'underline' : 'none'
  };

  return (
    <a href="/" style={styles}>Click me</a>
  );
}

However, things like :hover styles or media queries are not possible with this strategy. There are tools like Radium that can solve these issues, but I don't have experience with those.

CSS Modules

Another approach is to include stylesheets on a per-component basis. With CSS Modules, you write your CSS with the premise that what you write is local by default. You could make some rules global, but you have to do that explicitly by wrapping selectors in a :global function. For example: style.css:

.menu {
  padding: 20px;
  a {
    color: #fff;
    :global(.icon) {
      width: 16px;
    }
    &:hover {
      text-decoration: underline;
    }
  }
}

menu.js:

import styles from './style.css';
...
<ul className={styles.menu}>
  <li>
    <a href="/"><svg className="icon">...</svg></a>
  </li>
</ul>

While this is a good approach, it can be hard to keep things organised because you need at least two files for a styled component (a JS and a CSS file).

Styled components

There it is, my personal favourite way of styling in React: Styled components. This method relies heavily on tagged template literals, an ES2015 feature. The description of template literals on MDN says:

"Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them".

Tagged template literals however allow you to parse them with a function. For example:

function func(strings, param1) {
  return strings[0] + param1 + strings[1];
}
const verb = 'are';
func`tagged template literals ${} fun`;

The strings arguments contains all the strings, while the following arguments contain the expressions inside the template literals. (read more about the magic behind styled components)

So with styled components, you can write you styles as following:

const Button = styled.a`
  background: blue;
  color: white;
`;

And because we can use expressions inside template literals, we are able to check props, or evaluate other code:

const Button = styled.a`
  background: ${props => props.active ? 'red' : 'blue'};
  color: white;
`;

It is even possible to turn other components into a styled component, as long as the unstyled component accepts a className property:

const SimpleButton = ({ className, children }) => (
  <button className={className}>{children}</button>
);
const StyledButton = styled(SimpleButton)`
  background: blue;
`;

It's possible to use several features that CSS preprocessors provide inside the styles that are written in the template literal. For example nesting is possible, so the downsides of inline styles (like lacking of media query support) that I mentioned earlier can be handled as well:

const Button = styled.a`
  background: ${props => props.active ? 'red' : 'blue'};
  color: white;
  @media (max-width: 800px) {
    background: gold;
  }
  &:hover {
    text-decoration: underline;
  }
`;

If you set up everything like this, you'll end up with many styled components, and compose your React app with just styled components. A <Navbar> component could look like this:

const Navbar = () =&gt;
  &lt;div&gt;
    &lt;Logo /&gt;
    &lt;Menu wide&gt;
      &lt;MenuItem&gt;&lt;MenuLink to="/"&gt;Home&lt;/MenuLink&gt;&lt;/MenuItem&gt;
      &lt;MenuItem active&gt;&lt;MenuLink to="/about"&gt;About&lt;/MenuLink&gt;&lt;/MenuItem&gt;
      &lt;MenuItem&gt;&lt;MenuLink to="/contact"&gt;Contact&lt;/MenuLink&gt;&lt;/MenuItem&gt;
    &lt;/Menu&gt;
    &lt;Search /&gt;
  &lt;/div&gt;;

To come to a conclusion: Styled Components solve many of the earlier mentioned problems with CSS: * Scoping: No global styles, so no unwanted side effects; * Variables: You just could you javascript object literals and pass them to your styles; * Functions: you can just use javascript functions; * Nesting: Styled Components supports nested selectors; * Prefixing: Styled Components adds vendor prefixes to all necessary properties;

I don't event want to write styles in another way anymore 😄

.

.

.

.

👉🏻 Do you want to help us writing more awesome code? Contact us!

We love code