DEV Community

Cover image for Let's Take a Look at CSS in JS with React in 2019 - Styled Components
Phil Tietjen
Phil Tietjen

Posted on • Edited on

Let's Take a Look at CSS in JS with React in 2019 - Styled Components

Hey everyone! It's that time again to look at some cool CSS in JS with react. As this series has started rolling I've been trying to think a good way to structure these entries in an interesting and informative way. I've been trying to keep things based on my personal experiences with it; that's not going to change, but I've been conflicted about how deep I should go into the functionality without creating a less polished copy of their whole documentation. Based on some things I've been seeing in the comments in the React-JSS entry I'm going to try to go a little deeper into things.

Thank you, everyone, who has come to check out the series so far and left great comments and reactions. I hope to continue seeing comments for feedback, discussions, and questions! You all rock!

gif: dante claps with a heart of arrows behind him

What is Styled-Components?

As per usual, the best way for us to really know what this is let's check out the docs!

styled-components is the result of wondering how we could enhance CSS for styling React component systems.

I think this description does a better job selling than explaining so I'm going to try to unpack it so bare with me.

styled-components allows you to describe your styles with CSS in our React components.

This is probably the closest we are to actual CSS in JS; at least with React specifically, let's take a look at a quick example using our handy green button and inline styling as a baseline to compare.

Inline Styling

// Button.js
import React from 'react'

const Button = () => {
  const buttonGreen = {
    backgroundColor: "green",
    border: "2px solid white",
    borderRadius: "2rem"
  };

  return(
    <button style={buttonGreen}>
      I think I'm green
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode

Styled Components

//  Button.js
import React from 'react'
import styled from 'styled-components'

const ButtonGreen = styled.button`
  background-color: green;
  border: 2px solid white;
  border-radius: 2rem;
`

const Button = () => {
  return(
    <ButtonGreen>I think I'm green</ButtonGreen>
  )
}
Enter fullscreen mode Exit fullscreen mode

gif: Dante dancing

How did the implementation change?

  • We imported styled from the styled-components package.
  • We defined our ButtonGreen variable using styled.button.
  • We described our styles in ButtonGreen with CSS syntax!
  • We use ButtonGreen as the component root in our Button component.

Before we go further, let's do a little unpacking with what's happening here.
When we defined our ButtonGreen variable we made sure to use pascal case as opposed to our inline counterpart using camel case. This is because with styled we are defining a component to be used instead of passing a value into an attribute or prop. The .button on line 5 is the HTML element we are choosing as the root element of our ButtonGreen, and you can use any HTML element in this chain. The outcome of this generates an HTML element we defined as the root with a hashed className.

Let's also take a look at comparing our trusty Button component from last time with props affecting our styles.

Using Props with Inline Styling
// Button.js
import React from 'react'

const Button = ({backgroundColour, children}) => {
  const buttonStyles = {
    backgroundColor: backgroundColour,
    border: "2px solid white",
    borderRadius: "2rem"
  };

  return(
    <button style={buttonStyles}>
      {children}
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode
Using Props with Styled Components
//  Button.js
import React from 'react'
import styled from 'styled-components'

const Button = styled.button`
  background-color: ${props => props.backgroundColour};
  border: 2px solid white;
  border-radius: 2rem;
`

const Button = ({backgroundColour, children}) => {
  return(
    <Button backgroundColour={backgroundColour}>
      {children}
    </Button>
  )
}
Enter fullscreen mode Exit fullscreen mode

How did the implementation change?

  • We passed a prop called backgroundColour to our styled component
  • We referenced our backgroundColour prop value with an arrow function in an interpolated string.

Phil's Highlights

There's a lot more functionality here to offer; I'm not going to go over everything as that is what the docs are for, but I am going to cover my favorite things. What we've seen so far already had me sold just from how clean everything is because when your components get big, they can get hard to read or retain their context. In my opinion, Styled-Components gives us a great foundation with little effort to make things easier.

Extending Styles From Components

So far, we've seen controlling styles of a component via props that allow us to create variations of a component with different styling. It's great giving a component the ability to have granular control over a specific CSS property but in my opinion, it does have a fairly messy flaw. As the number the style rules grow for a component, adding more props to specific style rules for a component on top of its props used for functionality really starts to pile up.

A possible future for our Button only using props
//  Button.js
import React from 'react'
import styled from 'styled-components'

const Button = styled.button`
  background-color: ${({backgroundColour}) => backgroundColour};
  border: ${({borderWidth}) => borderWidth } ${({borderStyle}) => borderStyle} ${({borderColour}) => borderColour};
  border-radius: ${({borderRadius}) => borderRadius}$;
`

const Button = ({
  backgroundColour, 
  borderWidth, 
  borderStyle, 
  borderColour, 
  borderRadius, 
  onClick,
  children
}) => {
  return(
    <Button 
      backgroundColour={backgroundColour}
      borderWidth={borderWidth}
      borderStyle={borderStyle}
      borderColour={borderColour}
      borderRadius={borderRadius}
      onClick={() => onClick()}
    >
      {children}
    </Button>
  )
}
Enter fullscreen mode Exit fullscreen mode

I know I know, no one really uses different border styles other than solid. Our very basic button has a lot of props for what it needs to do and will only get bigger and scarier. In my opinion, this is best suited for dynamic styles or special cases.

Extending off of Button to make a variation
//  SignUpButton.js
import React from 'react'
import styled from 'styled-components'
import Button from '../components/Button'

const SignUpButton = styled(Button)`
  margin: 1rem;
  border-radius: 4rem;
  font-weight: bold;
  color: #fff;
  backgroundColour: "spring green";
`
Enter fullscreen mode Exit fullscreen mode
// SomePage
import React from 'react'
import SignUpButton from '../components/SignUpButton'

const SomePage = () => (
  <div>
    ...
    <SignUpButton>Sign up now</SignUpButton>
    ...
  </div>
)
Enter fullscreen mode Exit fullscreen mode

This is one of my favorite functionalities with the styled API. We're able to extend from the styled Button component and create a variation that can add additional styles or overwrite the existing styles we're basing off of; without adding extra props or classes causing the application to have what I like to call a specificity complex. I find this great for splitting a reusable variation into its own file or needing to apply one-off styling when needed without changing the original Button.

Rendering a Styled Component "As"

What if we wanted to render our Button with a different root HTML element without creating a different component or modifying the Button's render?

We can do that with the wonderful prop every Styled component gets called as

Rendering Button as an anchor
// SomePage
import React from 'react'
import Button from '../components/Button'

const SomePage = () => (
  <div>
    ...
    <Button as="a" href="#LearnMore">Learn More</Button>
    ...
  </div>
)
Enter fullscreen mode Exit fullscreen mode

Minus the potential added prop for href, we don't need to do any heavy refactoring of our Button component and remains fairly basic to its needs.

What Do I Personally Like About Styled Components

I've been using Styled Components for a while now, and even though this is early in the series, I think it may be my favorite CSS in JS solution for React. It's one of the reasons I set out to do this series because I needed more of an excuse to see what else is out there; if anything can top it for me.

Describing CSS with CSS

Object styles abstracted things just enough for it to be cumbersome, so being able to just use regular CSS syntax is great. It's especially great when you're converting CSS rules over to styled-components as for the most part it's copy and paste! There's not really much else to say about it.

Everything Is Components!

With the styled API, you end up with a lot more contextually named styled-components, which personally, I find much easier to understand what is going on and why in a component. Everything feels that much more declarative like React is intended.

What Do I Personally Dislike About Styled Components

Messy React Nodes

If you take a peek into the component's view in the react dev tools, you'll notice your styled-components will have some crazy nesting of context providers. I'm not sure if this really affects too much, maybe some unneeded rendering.

However, not to dismiss this dislike point but in the upcoming version, 5 is fixing this issue and can already be checked out if you install the 5 beta.

Would I Use Styled Components?

Yes. It's my number 1 choice currently.

Shout out to Emotion

Some of you may have been screaming at your screens reading this, fingers itching to comment "PHIL, WHAT ABOUT EMOTION?". WELL EMOTION SUCKS!

I'm joking.

Emotion is another CSS in JS solution and offers a little more of a diverse API. Included in that is their emotion/styled API which is conveniently compatible with styled-components API; they're either bitter rivals or best pals. With this, you can pretty much switch between the 2 libraries as you need to with no worry, yet.

I held off mentioning Emotion so I didn't have to use both library names. I will not be making an entry for emotion since I'll just be covering mostly the same stuff.

This marks the end of the entries of libraries I have prior experience with so going forward will be all new territory. If you have any recommendations for what to look at next give me a shout in the comments!

Time For The Plug

Friday Night Deploys Podcast by The Devplebs

We've Started a Podcast!

Keith Brewster and Phil Tietjen are 2 Canadian Web Developers and friends who decided to start what may be best described as a web development-focused and personality-driven podcast show called "Friday Night Deploys". It's a weekly show aimed to release every Friday where we share our experiences and stories about related topics and what we typically get up to in our lives.

Where To Listen

Spotify: https://open.spotify.com/show/7oXdJ5aETg5GBSNC6jZSNq
Itunes: https://podcasts.apple.com/ca/podcast/friday-night-deploys/id1485252900
Google Play Music: https://play.google.com/music/m/I54hbbplhdmovo2so6cxsctkcaq?t=Friday_Night_Deploys
PodBean: https://devplebs.podbean.com/

Where To Reach Us

Twitter: https://twitter.com/DevPlebs (DM's or Mentions welcome)
Email: devplebs@gmail.com

We hope you have fun listening and to hear from you!

Top comments (10)

Collapse
 
dyland profile image
Dylan Davenport

This may be a noob question (because I’m a React noob 😅) but why are styled components preferred over importing a CSS style sheet? I feel like that would keep our component files cleaner by not having so much extra code for the styles.

Collapse
 
phizzard profile image
Phil Tietjen • Edited

Hey Dylan,

Ultimately I think it comes down to what the application needs from how big it may be, how many developers are contributing, etc. However, if it's less or cleaner code we're worried about there are a number of things to consider down the road with CSS vs Styled Components.

If you're just importing one CSS stylesheet, then off the bat in our JS we technically have less code for our styling because all we have is our import './style.css' line and the rest are className="some-class". Although, there may come a time where we might need to modify styles based on state or props in our react component which can lead us down to potentially adding logic to our components to adjust for this. In larger projects can lead to some messy components.

I think what might be a better way to think about styled-components over CSS is that it aims to align itself better with Reacts component-based architecture with scoping styles but also giving you an API that is intended to work well with Reacts component API and patterns, ideally, resulting in a cleaner codebase for your components and your styling.

My first entry in the series may be more helpful for a "Why not use CSS?" question, as I go more into CSS vs CSS in JS for React!

I hope it answers your question and thanks for asking it! :D

Collapse
 
dyland profile image
Dylan Davenport

Yes that helps immensely! I’ve done one React project so far and it wasn’t huge so as you said depending on the project size I was able to safely use a stylesheet without issue. I can totally see how that can become a problem as projects become more complex though.

Collapse
 
adrianhelvik profile image
Adrian

For regular CSS: You get rid of global styles.

Say you write a component somewhere that uses the className 'container'. Then you can't use it in any other component style sheet without getting a conflict.

With CSS modules that is not a problem. The selling point against CSS modules is that you get more power. It lets you conditionally apply styles and build styles based on props.

Collapse
 
cristianbote profile image
Cristian Bote

Hey Phil, really good article! Loved the personal touch to it. Can I suggest the next package? 🙂 It's called goober github.com/cristianbote/goober. Yeah I know, I'm biased 🎉

But my intention is to offer a lightweight solution to a pattern that gives you so much freedom in terms of styling. The web it's large, and one should be careful whenever it builds something, to make sure that whatever you are sending down the wire is small and powerful.

That's goober in a nutshell. A css-in-jss solution in less than 1KB.

Really curious what your thoughts are.

Cheers!

Collapse
 
phizzard profile image
Phil Tietjen

Hey Cristian,

Thanks a lot! I'm glad you enjoyed the article, I try to give the majority of my posts some personal touches.

I will definitely be checking out goober and consider it for the next post! :D

Brilliant job on the 339 github stars and after checking out the docs it looks awesome! (1KB + styled API sounds incredible).

Honestly, this is one of the things I was really hoping for doing this series was to find other solutions that may be newer, less popular, or hidden under the popular go-to solutions.

Thanks for the comment and the recommendation!

Collapse
 
mvrs profile image
Marlon Johnson

The only thing I don't like about styled-components is the huge nested issue when it comes to debugging. With regular CSS/SASS it's easier to pinpoint which class belongs to what component via styles.scss.

Collapse
 
phizzard profile image
Phil Tietjen

Hey Marlon,

I think with the right structure for either approach can minimize debugging issues. I think where styled-components gets an edge is that because it's scoped, Ideally, you would only need to be concerned with it residing in the component's directory.

I typically create a style.js file where I define and export all my styles for my component to import
/ Component
--/ index.js
--/ Component.js
--/ style.js

I hope you enjoyed the read!

Collapse
 
codybrewer profile image
CodyBrewer

Fantastic Read Phil! I love Styled-Components and this article definitely builds on that. This is a great run through for anyone that is interested in Styled-Components and I will be sending this to anyone who asks about it before they dig into the docs.

Collapse
 
phizzard profile image
Phil Tietjen

Hey CodyBrewer,

Thanks a lot! Really glad you enjoyed the read! :D

I also love Styled Components and had a great time writing about the things I like to use in their API.