Menu Search
Jump to the content X X
Smashing Conf San Francisco

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf San Francisco, dedicated to smart front-end techniques and design patterns.

Styled-Components: Enforcing Best Practices In Component-Based Systems

Building user interfaces on the web is hard, because the web and, thus, CSS were inherently made for documents. Some smart developers invented methodologies and conventions such as BEM, ITCSS, SMACSS and many more, which make building user interfaces easier and more maintainable by working with components.

After this shift in mindset towards building component-based user interfaces, we are now in what we like to call the “component age.” The rise of JavaScript frameworks such as React, Ember and recently Angular 2, the effort of the W3C to standardize a web-native component system, pattern libraries and style guides being considered the “right way” to build web applications, and many other things have illuminated this revolution.

A screenshot of styled-components code1
A Button React component written with styled-components. (View large version2)

Best Practices In Component-Based Systems Link

As we’ve built more and more apps with components, we’ve discovered some best practices when working with them. I want to talk about three main ones today: building small, focused and independent components; splitting container and presentational components; and having single-use CSS class names.

Build-Small Components Link

Instead of relying on classes for composition, use components to your advantage and compose them together! For example, imagine a Button component that renders <button class="btn"> to the DOM. One could also render a bigger, more important button. Making a bigger button would be as easy as attaching the btn--primary class in the DOM: <button class="btn btn--primary">.

Instead of forcing users of the component to know which particular class to attach, the Button component should have a primary property. Making a primary button would be as easy as <Button primary />! Here is how we could implement this:

// Button.js

function Button(props) {
  const className = `btn${props.primary ? ' btn—-primary' : ''}`
  return (
    <button className={className}>{props.children}</button>
  );
}

Now, users no longer need to know which particular class it applies; they just render a primary button! What happens when the primary property is set is an implementation detail of the component. Changing the styling, classes or behavior of the button now requires editing only a single file where the component is created, instead of hundreds of files where it is used!

Split Container and Presentational Components Link

With React, some of your components may have state associated with them. Try to split components that handle data and/or logic (for example, data formatting) from components that handle styling. By separating these two concerns, reasoning about changes in your code base will be a lot easier!

If the back-end API format has to change, all you have to do is go into your container components and make sure you render the same presentational components as before, even with the new format, and everything will work perfectly fine!

On the other hand, if the visual design or user experiences of your app have to change, all you have to do is go into your presentational components and make sure they look correct on their own. Because these components don’t care about when and where they’re rendered, and you haven’t changed which components get rendered, everything will work perfectly fine!

By separating these two types of components, you avoid doing multiple unrelated changes at the same time, thus avoiding accidental errors!

Have Single-Use Class Names Link

Going back to our Button component, it has a .btn class. Changing the styles of that class should not affect anything except the Button! If changing the background-color in my .btn class messes up the layout of the header and gives the footer two columns instead of three, then something is wrong. That violates the entire premise of having independent components!

This essentially boils down to using every class in your CSS only once (outside of “mixins” like .clearfix). This way, bugs like the one above can never happen.

The problem, as always, is us humans. Ever encountered a bug in a program? It was only there because a human put it there. If programs could exist without humans, then bugs would not be a thing. Human error accounts for every single bug you’ve ever found and squashed.

There is a famous joke3 in the front-end development world:

Two CSS properties walk into a bar. A barstool in an entirely different bar falls over.

The reception and repetition this joke has gotten tells you how many developers have seen this type of bug before. It happens, especially in teams, no matter how hard you try to avoid it.

With that and a few other things in mind, Glen Maddern4 and I sat down and started thinking about styling in this new era. We didn’t want to reinvent or get rid of CSS; it’s a language that’s made for styling and that browsers natively support! Let’s instead take the best parts of CSS and make human error in component-based systems almost impossible.

Enforcing Best Practices Link

The basic idea of styled-components is to enforce best practices by removing the mapping between styles and components. If you think about any styling method you’ve used, there is always a mapping between a style fragment and your HTML.

With standard CSS, this would be a class name (or maybe an ID). With styles in JavaScript libraries in React, it’s either setting a class from a variable or passing a JavaScript object to the style property.

Because we want to use each class only once, what if we just removed that mapping?

As it turns out, by doing so, we also enforce the split between container and presentational components, and we make sure that developers can only build small and focused components!

Another interesting feature of styled-components is that it allows you to write actual CSS in your JavaScript (not just CSS-as-JavaScript objects). It leverages an infrequently used feature of ECMAScript 2015 (the new version of the JavaScript standard), called tagged template literals, to make that work a pleasant experience for the developer.

The Basics Link

Now, you might be wondering what that looks like. Well, let’s take a look!

const Title = styled.h1`
  color: palevioletred;
  font-size: 1.5em;
  text-align: center;
`;

You can now use this React component like any other:

<Wrapper>
  <Title>Hello World, this is my first styled component!</Title>
</Wrapper>
A screenshot showing the text 'Hello World, this is my first styled component!' in palevioletred and centered on a papayawhip background.5
This is what the component above looks like in the browser. (View live demo6) (View large version7)

Quite a few things are going on here, so let’s dissect this code snippet.

styled.h1 is a function that, when called, returns a React component that renders an <h1> into the DOM. If you’re wondering, “Where do we call that function? I see only backticks, no parentheses!” that’s exactly where the ECMAScript 2015 features come into play.

What you’re seeing above is a tagged template literal8, which is a new feature of JavaScript the language! (No special tooling is needed to use styled-components.) You can call functions with backticks (like styled.h1``), and they will receive the string passed in as the first argument. As we go along, you’ll see how this differs from calling functions normally with parentheses, but let’s leave it at this for now!

So, this styled.h1 call returns a React component. This React component has a class attached to it that styled-components automatically generates and uniquifies. This class name has the styles associated with it that you pass to the template literal!

Summed up, this means that the styled.h1 call returns a React component that has the styles applied that you pass to the template literal!

Full CSS Support Link

Because styled-components is just CSS, it supports all of CSS perfectly fine! Media queries, pseudo-selectors, even nesting just work! We are generating a class name and injecting the CSS into the DOM; so, whatever works in CSS works with styled-components, too.

const Input = styled.input`
  font-size: 1.25em;
  border: none;
  background: papayawhip;
  /* ...more styles here... */

  &:hover {
    box-shadow: inset 1px 1px 2px rgba(0,0,0,0.1);
  }

  @media (min-width: 650px) {
    font-size: 1.5em;
  }
`;

This Input component will now have nice hover styles and will resize itself to be a bit bigger on large screens. Let’s see what one of these inputs looks like with and without a placeholder:

One input without any content showing the placeholder, and one with some content9
This is what the component above looks like in the browser. (View live demo10) (View large version11)

As you can see, making a container component that has styling or making a presentational component that has logic is impossible. We are also building a lot of small components and combining them into bigger containers, and because there are no visible classes, we cannot use them more than once!

Essentially, by using styled-components, we have to build a good component system — there is no other way! It enforces the best practices for us — no special architectural code review needed.

Wrapping Up Link

Styled-components offers a lot more great features, such as built-in theming and full React Native support. I encourage you to dive into the documentation12 and try it out on one of your projects! Not having to worry about best practices makes the development experience so much better and quicker. I’m obviously very biased, but I don’t ever want to go back to another way of styling React apps.

Here are a few miscellaneous links related to styles in JavaScript that aren’t specific to styled-components but that talk about the topic more generally:

  • React JS Style Components13” (video), Michael Chan, Full Stack Talks
    An amazing talk about leveraging components as a styling construct. If you’re using React and haven’t heard this talk yet, stop what you’re doing and watch it right now!
  • The magic behind 💅  styled-components14“, Max Stoiber
    This article by yours truly dives deep into tagged template literals, how they work and why they are super useful, based on the example of styled-components.
  • The Future of Reusable CSS15” (video), Glen Maddern, ColdFront16
    This talk by styled-components’ cocreator doesn’t talk about the library itself, but explains how theming component-based systems should work. A lot of these ideas have made their way into the library!
  • Rendering Khan Academy’s Learn Menu Wherever I Please16,” Jordan Scales
    A great article that documents the move of a complex code base from a Handlebars and LESS combo to React and styles in JavaScript. Highly recommended if you’re not sure whether either React or Styles in JavaScript are for you!

(rb, vf, il, yk, al)

Footnotes Link

  1. 1 https://styled-components.com
  2. 2 https://www.smashingmagazine.com/wp-content/uploads/2016/11/code-atom-opt.png
  3. 3 https://twitter.com/thomasfuchs/status/493790680397803521
  4. 4 https://twitter.com/glenmaddern
  5. 5 http://www.webpackbin.com/VkbO4mdR-
  6. 6 http://www.webpackbin.com/VkbO4mdR-
  7. 7 https://www.smashingmagazine.com/wp-content/uploads/2016/11/hello-world-opt.png
  8. 8 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals
  9. 9 http://www.webpackbin.com/EyeFgWxef
  10. 10 http://www.webpackbin.com/EyeFgWxef
  11. 11 https://www.smashingmagazine.com/wp-content/uploads/2016/11/input-opt.png
  12. 12 https://github.com/styled-components/styled-components
  13. 13 https://www.youtube.com/watch?v=gNeavlJ7lNY
  14. 14 https://mxstbr.blog/2016/11/styled-components-magic-explained/
  15. 15 https://www.youtube.com/watch?v=XR6eM_5pAb0
  16. 16 https://medium.com/@jdan/rendering-khan-academys-learn-menu-wherever-i-please-4b58d4a9432d#.w9nshye05

↑ Back to top Tweet itShare on Facebook

Max works as an open source developer at Thinkmill, where he takes care of KeystoneJS and ElementalUI. He's also the creator of react-boilerplate, the co-creator of Carte Blanche and a co-organiser of the React Vienna Meetup. He loves travelling the world, brewing amazing coffee, skiing big mountains and making things on the web.

  1. 1

    Great article and a practical way of designing/developing your JS components. Vue JS has promoted this concept for awhile now with single file components and it has been a pleasure to develop with.

    4
  2. 2

    Thank you very much for the effort and energy you and Glenn have put into styled-components. I decided to introduce styled-components to my project about two weeks ago, and for me, it absolutely feels right – no turning back now! I already see the tremendous benefits of removing the mapping between CSS and styles mentioned in this article. However, while debugging with Chrome React Developer Tools, I find myself longing for the ability to search by component name. I see lots of styled.div and styled.li components. Is there something I could be doing differently to help with that?

    5
    • 3

      Thank you very much for the kind words!

      We have run into this ourselves for the past months, and we’re hard at work on a) a babel plugin and b) v2 of styled-components which will together solve this problem forever by attaching the displayName of the component and putting it into the className too!

      For this component code:

      const StyledButton = styled.button``

      In your normal DevTools you’ll see

      <div class="StyledButton__asdf123 asdf123" />

      And in the React DevTools you’ll see

      <StyledButton className="StyledButton__asdf123 asdf123" />

      Give us a few more weeks (hopefully we’ll get it done in January, but it might be February) and this’ll never be a problem again! 😊

      14
  3. 4

    Joseph Zimmerman

    January 16, 2017 5:22 pm

    I’ve seen a couple articles about styled-components now and I still haven’t seen an example with actual functionality. How do you handle that other than onclick? Do you use a wrapper component?

    0
    • 5

      aminimalanimal

      January 16, 2017 6:31 pm

      How do you handle that other than onclick?

      The styled component doesn’t handle any sort of event handling.

      Do you use a wrapper component?

      Well, all of the elements you render in React eventually come from native HTML (or iOS). With styled-components, you use the following syntax to define that element:


      const ListItem = styled.li`
      list-item-type: none;
      `

      The styled.li portion is returning a native li element behind the scenes.

      ListItem is the name I’m going to use later on in the React component that handles functionality. You can place any of the normal attributes you want on it, like so (this is within another component’s render method:
      <ListItem
      aria-current="page"
      >
      {this.props.children}
      </ListItem>

      This renders:

      <li aria-current="page" class="aHdnWr">Home</li>

      The class above is generated by styled-components and is used in the stylesheet appended to the DOM.

      So yes, this ListItem is created exclusively to host styles, but it won’t add extraneous elements to the DOM (as I needed that li anyway), so it’s a wrapper in React, but not in the output.

      I started using this plugin on Thursday. It’s good stuff.

      3
      • 6

        aminimalanimal

        January 16, 2017 6:33 pm

        Hmm… sorry the output for that is a bit wonky, especially regarding the code blocks. Looks like those may not be properly supported by Smashing Magazine.

        1
  4. 7

    It would be great to see styled-jsx (https://github.com/zeit/styled-jsx) with all the features of styled-components.
    styled-jsx it’s the way to go, it’s more future-proof (it’s almost the same of using WebComponents), and has server side support.
    But lacks of react-native support, themes and dynamic styles features (which styled-components has).

    I hope that you and Guillermo Rauch start to working together!

    0
    • 8

      I’ve actually discussed with Guillermo at length about styling! We’re good friends 😊

      They aim to be as close to the future spec of web components as possible, to make switching over when it’s ready a simple operation, whereas we aim to provide the best experience for styling component-based systems. Ultimately, those are related but not the same goal.

      Sidenote: Server-side rendering support for styled-components is already implemented and will be out with v2, so sometime in February/January!

      3
  5. 9

    Alexander Kaiser

    January 17, 2017 9:41 am

    This article was published the exact same day when I evaluated using styled-components instead of JSS. Coincidence? :D

    1
    • 10

      Alexander Kaiser

      January 17, 2017 10:08 am

      Sorry, my comment did not add anything useful to the discussion, so here are my thoughts why styled-components may be a “better” approach than JSS:
      – Write CSS as you’re used to. No rewrite of copy&pasted styles from stackoverflow ;D
      – Only one npm package needs to be updated, instead of a handful must-have plugins, that make JSS useful – in my scenario: jss, jss-camel-case, jss-default-unit, jss-nested, jss-vendor-prefixer, jss-global, react-jss

      Missing syntax highlighting was an issue at first. For now I’m happy with language-babel for Atom, still in need of a Webstorm/IntelliJ plugin though.

      To evaluate which CSSinJS-problem-solver is for you, check this: https://github.com/styled-components/comparison

      Thank you Max for all your talks and work. You bring so much value to us all! :)

      0
    • 11

      Definitely not a coincidence, all part of an elaborate ploy 😉

      Just kidding, have you seen my ReactNL keynote where I announced styled-components? I talk about all the popular, existing solutions, why none of them fit all of my needs and how styled-components is different: https://m.youtube.com/watch?v=19gqsBc_Cx0

      3
      • 12

        Alexander Kaiser

        January 17, 2017 10:26 am

        Well, this talk is actually in my watchlist! This will help me a lot presenting styled-components to my coworkers. Thank you so much Max for all your excellent talks and work! :D

        0
  6. 13

    When did it become best practice to remove the cascading from CSS?

    I agree with your first 2 points, but not the third. It definitely works and has some advantages; but I’m unconvinced from this article that it is best practice, or even a good idea.

    11
  7. 14

    @Ben It’s not that the cascade is bad, it’s just that cascade everywhere, all the time by default is bad.

    You can still use global, cascading libraries e.g. Bootstrap, if you need that. But your component’s styles should be isolated and never affect, or be affected by the styles of other components. This interaction is IMO, what caused much of the trouble with CSS and gave it the bad name that brought to this point.

    1
  8. 15

    This is great but how does this play when using in a design system where it’s much easier to add classes to elements rather than inline all the css? If everything is unique to the component then you wouldn’t even be able to build a design system based on reusable classes. I’m curious to hear what are people’s approaches with component embedded styles and design systems?

    4
    • 16

      I’m really curious about this too. I was struggling with this issue on Polymer. Particularly, when designing theming systems that needed to be superficially themed for those who didn’t or shouldn’t have access to the JS.

      3
  9. 17

    Gustavo Woltmann

    January 21, 2017 1:12 pm

    I never used this kind of style component before and I learned new things from your blog. Everyday I spent some time on internet to learn new things in glad I found your blog.

    0
  10. 18

    Very intriguing article, as I’m trying to put together ideas for how to build a new web app. Question: would this idea integrate with Tachyons, or are the two completely different? It seems Tachyons has the a similar goal of not reducing interdependencies and leak, while making the UI styling easier to debug.

    0

Leave a Comment

You may use simple HTML to add links or lists to your comment. Also, use <pre><code class="language-*">...</code></pre> to mark up code snippets. We support -js, -markup and -css for comments.

↑ Back to top