Lewislbr

Get started with styled-components in a React and TypeScript app

When it comes to styling React applications, I really like the CSS-in-JS approach, and within this realm, styled-components is my favourite option. It provides automatic critical CSS, no class name bugs, easier deletion of CSS, simple dynamic styling, painless maintenance, and automatic vendor prefixing. All of that while writing pure CSS inside template literals.

Installation

We'll begin by installing styled-components itself, a Babel plugin that provides CSS minification, enhances CSS class names, and helps minifiers remove unused code, among other benefits, and the TypeScript types:

npm i -D styled-components babel-plugin-styled-components @types/styled-components

Then we have to add the plugin to our Babel configuration file:

{
  ...
  "plugins": [
    [
      "babel-plugin-styled-components",
      {
        "pure": true
      }
    ]
  ]
}

Usage

Now we can create a styled component, which is actually a React component with attached styles to it, by declaring a constant and passing the CSS styles as arguments to a styled tag function for the element we want to create:

import styled from "styled-components"

const Button = styled.button`
  background-color: black;
  color: white;
  padding: 10px 30px;
`

We have created a styled component called "Title" that's a button HTML tag, which will result in:

<button class="Button-d7341x-1 jtJbWl"></button>
.jtJbWl {
  background-color: black;
  color: white;
  padding: 10px 30px;
}

The class names are generated to avoid duplications and conflicts, and thanks to the Babel plugin, we have them prefixed with the component name, to help us identify where they come from.

Depending on the modularity of our components, it can be helpful to distinguish between styled (or presentational) components that just define the styles of the elements, and compound (or container) components that are made of various styled components and handle logic or data.

We can define the styled components wherever we want:

  • In a separate file containing the styled components a compound component needs and importing them into it (useful when a compound component has many unique styled components):
import styled from "styled-components"

export const Box = styled.div`
  display: flex;
  justify-content: center;
  margin: 0 auto;
`
export const Button = styled.button`
  background-color: black;
  color: white;
  padding: 10px 30px;
`
export const Title = styled.h1`
  color: darkgray;
  font-size: 32px;
  text-align: center;
`
import React from "react"
import {Box, Text, Title} from "./CompoundComponent.styles.ts"

function CompoundComponent(): JSX.Element {
  return (
    <Box>
      <Title>styled-components is great!</Title>
      <Button>I agree</Button>
    </Box>
  )
}
  • All in the compound component file (not recommended, it can get messy really quickly):
import React from "react"
import styled from "styled-components"

const Box = styled.div`
  display: flex;
  justify-content: center;
  margin: 0 auto;
`
const Button = styled.button`
  background-color: black;
  color: white;
  padding: 10px 30px;
`
const Title = styled.h1`
  color: darkgray;
  font-size: 32px;
  text-align: center;
`

function CompoundComponent(): JSX.Element {
  return (
    <Box>
      <Title>Join the styled-components club</Title>
      <Button>OK</Button>
    </Box>
  )
}
  • In a unique file for each styled component (useful when each styled component is used by many compound components):
import styled from "styled-components"

export const Box = styled.div`
  display: flex;
  justify-content: center;
  margin: 0 auto;
`
import styled from "styled-components"

export const Button = styled.button`
  background-color: black;
  color: white;
  padding: 10px 30px;
`
import styled from "styled-components"

export const Title = styled.h1`
  color: darkgray;
  font-size: 32px;
  text-align: center;
`
  • In a single styles file that acts as a source of styled components for all compound components (useful when each styled component is used by many compound components, but every name must be unique):
import styled from "styled-components"

export const Box = styled.div`
  display: flex;
  justify-content: center;
  margin: 0 auto;
`
export const Button = styled.button`
  background-color: black;
  color: white;
  padding: 10px 30px;
`
export const Title = styled.h1`
  color: darkgray;
  font-size: 32px;
  text-align: center;
`

Conditional Styling

We can adapt styles based on props we pass to the styled component, giving us great flexibility to adapt each styled component for every need:

import React from "react"
import styled, {css} from "styled-components"

interface Props {
  secondary?: string
}

const Button = styled.button(
  (props: Props) =>
    css`
      background-color: ${props.secondary ? "dodgerblue" : "black"};
      color: white;
      padding: 10px 30px;
    `,
)

function CompoundComponent(): JSX.Element {
  return (
    <>
      <h1>Join the styled-components club</h1>
      <Button>OK</Button>
      <Button secondary>NO</Button>
    </>
  )
}

Styles Extension

We can also make variants of styled components by using an existing styled component as a base element to extend (or override) its styles with new ones:

import styled from "styled-components"

export const Button = styled.button`
  background-color: black;
  color: white;
  padding: 10px 30px;
`
export const ButtonLarger = styled(Button)`
  font-size: 2rem;
  padding: 20px 60px;
`

Global Styles

For styles that affect every other component, like base styles or a CSS reset, we can use the special tag function createGlobalStyle:

import {createGlobalStyle} from "styled-components"

export const GlobalStyles = createGlobalStyle`
  html
  body {
    background-color: white;
    color: black;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-size: 17px;

    @media (max-width: 600px) {
      font-size: 16px;
    }
  }

  /* CSS Reset */

  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body,
  h1,
  h2,
  h3,
  h4,
  p {
    margin: 0;
  }

  body {
    min-height: 100vh;
    scroll-behavior: smooth;
    text-rendering: optimizeSpeed;
    line-height: 1.5;
  }
`

And then we can import it in the root React component and place it at the top of the tree:

import React from "react"
import {GlobalStyles} from "./components"

export function App(): JSX.Element {
  return (
    <>
      <GlobalStyles />
      <main>
        <h1>styled-components is cool</h1>
        <p>Convinced yet?</p>
      </main>
    </>
  )
}

And that's the basics! I hope it makes sense to you and don't hesitate to take a look at the official documentation to learn more and advanced stuff.

If you use VS Code, you can install this extension to enable syntax highlighting for the styles inside template literals.



If you're using dark mode, do you like the code blocks's theme? I have it available for VS Code, feel free to check it.