The Basics of Styled Components

Nathan Thomas' avatar

by Nathan Thomas

15 min read

Image

Let’s Get the Party Started

It’s time to talk about something super awesome that might just change you spiritually.

Maybe.

No promises.

I want to show you how Styled Components work. According to the official website, Styled Components is a library of “CSS in JavaScript” that provides “visual primitives for the component age.” If that made no sense to you, that’s okay; in short, it’s a library that you install and import in React that allows you to componentize (yes, I know that’s not a word… sue me) styling for JSX elements inside your React component’s file.

I believe in trial by fire, so let’s go ahead and jump into the code we’ll be looking at today.

"The essence of style is a simple way of saying something complex."

- Georgio Armani

The Overview of a Styled Component

We’re going to be building out an App that renders some buttons. If you want to follow along in the article, you can using this CodeSandbox link. Let’s go ahead and see what our completed code in App.js looks like before we talk about what it does:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import styled, { css, keyframes } from "styled-components";

const buttonHover = keyframes`
  0% {
    opacity: 0.5;
  }
  100% {
    opacity: 1;
  }
`;

const Button = styled.div`
  background: #0d2728;
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  -webkit-appearance: none;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-family: sans-serif;
  font-weight: 700;
  height: 45px;
  margin: 80px auto 0;
  opacity: 0.5;
  width: 55%;
  &:hover {
    animation: ${buttonHover} 0.4s forwards;
  }
  ${props =>
    props.primary &&
    css`
      background: #0e30f0;
    `}
  ${props =>
    props.secondary &&
    css`
      background: #ff9697;
    `}
  @media (min-width: 500px) {
    width: 200px;
  }
`;

class App extends Component {
  render() {
    return (
      <div className="App">
        <Button>Main</Button>
        <Button primary>Primary</Button>
        <Button secondary>Secondary</Button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

I’m a visual person, so let’s also see what the code above renders to the screen. Here’s the buttons in their normal state:

Image

When we hover over them, they look like this:

Image

Nice. We have ourselves some awesomely-styled buttons. Let’s go ahead and walk through the code step-by-step in order to understand what each part of our Styled Components code does.

How Installs and Imports Work

Okay, so let’s say we have a brand new React app that we’ve created; how do we even begin? First, you need to install Styled Components inside your application directory using one of these two commands:

yarn add styled-components

or

npm install styled-components

You should use whichever service (yarn versus npm) you used to create your React application. It might take a minute to install once you run one of those on the command line, so I’ll wait here while you get coffee.

When you get back, you’ll then want to import Styled Components into a component to be used to style it out. Here’s the import syntax:

import styled from "styled-components";

That wasn’t so bad, was it? The next thing you want to do is to drop that bad boy into your component next to any other imports. I’m going to drop mine into my App.js file like so:

import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";

How to Write a Basic Styled Component

Now that we’ve imported Styled Components as shown above, we’re going to make a simple button component that can conditionally render different colors (based on props) as well as incorporate animations. This is the code that we’ll place inside App.js underneath our import statements:

const Button = styled.div`
  background: #0d2728;
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  -webkit-appearance: none;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-family: sans-serif;
  font-weight: 700;
  height: 45px;
  margin: 80px auto 0;
  opacity: 0.5;
  width: 200px;
`;

You might look at this and think, “I recognize the CSS code inside that code block, but what is going on with what’s wrapped around it?” This seemed like black magic to me when I first saw it, so I’ll take it slow and explain what every part of this component is doing from the beginning.

First off, we are defining a const variable in JavaScript, Button, that calls Styled Components to create a div. Second, we are using two back-ticks to call a function (this part is key) to have Styled Components render the HTML element we’ve chosen. (The back-ticks calling a function is similar to the way JavaScript renders a Template Literal elsewhere, in case you’re curious.)

At this point, our component looks like this:

const Button = styled.div`
  // We're about to put code here
`;

Now that we have our component all ready to go, we can drop any valid CSS code inside it and have it render when we call this component in the JSX. When we do that, we’ll have the button component up above at the start of this section.

After inserting that CSS code block back in, let’s go ahead and use our new button component by placing it in our JSX so that it displays out in our app!

How to Use the Component in Your JSX

Now that we’ve built our basic button component, we want to use it. Let’s go ahead and place it inside our JSX in App.js like so:

class App extends Component {
  render() {
    return (
      <div className="App">
        <Button>Main</Button>
      </div>
    );
  }
}

Nice!

We’re using our component. You can place stuff you create with Styled Components inside your JSX as a component just the same as when you import and use other separate functional or class components in React. When we take a look in our browser, it should look like this:

Image

However, this isn’t quite good enough. Let’s add a few more features to our button(s) to spice them up!

Image

Conditional Rendering and Hovering

We’re in a really good spot with our component so far, but we could be doing so much more with it. For instance, one thing that we lost in translation (so far) when we set up this component was that we don’t have a hover feature or any conditional rendering like you might have previously used in SASS or LESS inside React.

If we want to get those features back, here’s what we can write below the core CSS styles inside our component:

const Button = styled.div`
  background: #0d2728;
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  -webkit-appearance: none;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-family: sans-serif;
  font-weight: 700;
  height: 45px;
  margin: 80px auto 0;
  opacity: 0.5;
  width: 55%;

  ${props =>
    props.primary &&
    css`
      background: #0e30f0;
    `}
  ${props =>
    props.secondary &&
    css`
      background: #ff9697;
    `}
  @media (min-width: 500px) {
    width: 200px;
  }
`;

First-things-first, let’s knock out what’s easy to explain. All the way down at the bottom of the component (right above this paragraph), we have a media query; if you’ve written any vanilla CSS or used a preprocessor at all (and I’d be very surprised if you haven’t if you’ve made it to this point in the article), this should look familiar. Fortunately for us, we can write media queries inside our component and nest CSS styles inside of it just like in SASS or LESS.

The rest of the code that we’ve added looks a little more complicated:

${props =>
  props.primary &&
    css`
      background: #0e30f0;
    `}

${props =>
  props.secondary &&
    css`
      background: #ff9697;
    `}

That’s a lot of stuff to take in all at once. What’s going on here? Well, remember how these conditional styles are placed inside the double back-ticks that run a template literal-style function call? Because we’re doing that, we can interpolate our entire conditional statement inside a ${} just like any other time we use template literals.

Inside is, we are using an arrow function that is passing in props and checking to see if the prop primary (for the first conditional render) and secondary (for the second) are present. If these statements are true, then we are telling JavaScript to render out the CSS styles enclosed in additional double back-ticks.

There’s a couple of “gotchas” associated with this. First, you must import css from the Styled Components namespace like so:

import styled, { css } from "styled-components";

Second, these conditional statements are using Ternary Statements to evaluate whether or not to run their code. A normal ternary statement for some random problem in JavaScript might be written like this:

(someVariable === "value") ? "It worked!" : "This sucks.";

This would render "It worked!" if the statement before the ? evaluates to true and "This sucks." if it evaluates to false.

A lesser-known feature of ternary statements is that you can eliminate the second half of the statement (the falsy, or "This sucks.", part after the semicolon in the example above) for an assumed null value if the statement returns false simply by using && and, in this case, the css we imported from the Styled Components namespace in our import statement above. Our conditional statement now looks like:

$(props => props.secondary && css` background: #ff9697 `;

The final “gotcha” problem with using conditional statements to style a component is that you have to actually define the prop you’re passing in on the JSX tag you want to use it on. Here’s an example again of all three of our buttons shown at the start of the article; notice how I’m declaring the prop values of primary and secondary on the second and third buttons:

class App extends Component {
  render() {
    return (
      <div className="App">
        <Button>Main</Button>
        <Button primary>Primary</Button>
        <Button secondary>Secondary</Button>
      </div>
    );
  }
}

Our component (and its conditional rendering) has no idea these props even exist anywhere in the app unless we define them on the <Button /> JSX tag. When we declare them, we get differently styled buttons based on conditional rendering as we saw at the beginning of the article:

Image

Using Animations Inside a Component

The last thing that we should talk about is how to use animations. It’s actually quite simple. First, we must create a brand new component using the same process we used before:

const buttonHover = keyframes`
  0% {
    opacity: 0.5;
  }
  100% {
    opacity: 1;
  }
`;

You might notice the keyframes declaration being given to Styled Components when we run our template literal functional call to generate this animation component. That’s very perceptive of you.

Much like css in our conditional rendering example, we must import keyframes from the Styled Components namespace in order to be able to generate a CSS animation. Our import statement at the top of App.js now looks like this:

import styled, { css, keyframes } from "styled-components";

Finally, the only other thing that we have to do is include a CSS style for the animation inside any component in which we want to use it. The code we’ll paste into our buttons looks like this:

&:hover {
  animation: ${buttonHover} 0.4s forwards;
}

Once this is in our code, we will have a sweet, subtle hover animation that will really make our button feel nice.

Conclusion

I know this article was a long one, but I hope that you found it helpful. Styled Components is a powerful “CSS in JavaScript” library that you can leverage to build beautiful applications. If you have any questions (or if you just want to connect), please reach out to me using the social links below.

Thanks for reading. Here is an MGMT outro tune to jam to while you’re coding.

Nathan

Baby Yoda