DEV Community

Cover image for How to use Themes in styled-components
aromanarguello
aromanarguello

Posted on • Edited on

How to use Themes in styled-components

Styled-components is my default css-in-js library. I have used other libraries in the past but styled-components remains my personal favorite. I love the fact that I can embed and treat styles as if they were components. It gives me the ability to use maximum reusability. Additionally, I can pass props to these and make really cool conditional styles with minimum effort.

Theming is a great tool to use within front-end applications. It also allows me to write way less code and be more consistent with my styling. By leveraging the theme provider in styled-components I only need to write my main styles and rules in one single object and invoke them in any component that is a descendant of that provider. Theme provider achieves this by leveraging the context API.

This short guide assumes a basic knowledge of styled-components.

I created a code sandbox with only three files in it, but the Theme pattern I use can be added anywhere within the directory of your application.

Update June 2020: I hosted a small workshop where I show how to add styled-components with ThemeProvider to a react app. You can checkout the video here. If you want to skip directly to theme provider, you can jump to minute 26:27.

Given the following structure:

|_ public
|_ src
  |_ App.jsx
  |_ index.js
  |_ Theme.jsx // can go in any folder
|_ package.json

Enter fullscreen mode Exit fullscreen mode

App.jsx

import React from "react";

const App = () => {
  return (
      <div>
        <h1>Hello world!</h1>
        <h2>By the power of styled-components!</h2>
      </div>
  );
};
export default App;

Enter fullscreen mode Exit fullscreen mode

To begin with, inside of your react project install styled-components

npm install styled-components
Enter fullscreen mode Exit fullscreen mode

After I have set up my initial configuration and installed all my dependencies I usually go ahead and create a Theme.jsx component. In this component, I also create the theme object file. You can easily create this within your App.jsx component, but I think it is a good separation of concerns to allow it to live in its own file.

First things first, import React from the react dependency, and then we import ThemeProvider from the styled-components file. Theme provider uses context to provide the properties to its descendants.

import React from "react";
import { ThemeProvider } from "styled-components";
Enter fullscreen mode Exit fullscreen mode

Theme provider takes in a prop called theme, this props takes an object. We can add any property we want our styled-components to have access to. You can let your imagination run wild here! It is very powerful.

const theme = {
  colors: {
    powderWhite: "#FFFDF9",
    persianGreen: "#06B49A",
    lightBlue: "#AFDBD2",
    onyx: "#36313D"
  },
  fonts: ["sans-serif", "Roboto"],
  fontSizes: {
    small: "1em",
    medium: "2em",
    large: "3em"
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, using the render props method we will create a Theme component that will render children with all the properties from the Theme provider. Like I mentioned before, the theme provider takes a theme prop. In that prop is where we reference the object we create above.

const Theme = ({ children }) => (
  <ThemeProvider theme={theme}>{children}</ThemeProvider>
);
Enter fullscreen mode Exit fullscreen mode

Finally, we export the theme.

import React from "react";
import { ThemeProvider } from "styled-components";

const theme = {
  colors: {
    powderWhite: "#FFFDF9",
    persianGreen: "#06B49A",
    lightBlue: "#AFDBD2",
    onyx: "#36313D"
  },
  fonts: ["sans-serif", "Roboto"],
  fontSizes: {
    small: "1em",
    medium: "2em",
    large: "3em"
  }
};

const Theme = ({ children }) => (
  <ThemeProvider theme={theme}>{children}</ThemeProvider>
);

export default Theme;

Enter fullscreen mode Exit fullscreen mode

Back in our App.jsx the component, we now import the theme component that was just created to wrap our entire function. By wrapping our App function, all the descendants of App will have access to the theme object. I usually like to add it to the top level of my project.

We will also import the styled object. In a nutshell, the way we create styled-components is through this method. This method will give us back an HTML element that is mapped to the components and applies the give CSS styles.

import React from "react";
import Theme from "./Theme";
import styled from "styled-components"
const App = () => {
  return (
    <Theme>
      <div>
        <h1>Hello world!</h1>
        <h2>By the power of styled-components!</h2>
      </div>
    </Theme>
  );
};
export default App;

Enter fullscreen mode Exit fullscreen mode

Now, let's create some quick styled-components to highlight how we can access the theme within our styles. I also added props to <Heading> to illustrate how we can pass prop to our styles and use them to do things like conditionally render a font size, but you can do so much more. As I said, you can use your imagination 😁. You can perform any javascript operation. And because styled-components uses template literals, it all feels as if we were writing normal CSS.

import React from "react";
import Theme from "./Theme";
import styled from "styled-components";

const Container = styled.div`
  width: 100%;
  border: ${props => `1px solid ${props.theme.colors.onyx}`};
  background-color: ${props => props.theme.colors.lightBlue};
  font-family: ${props => props.theme.fonts[0]};
`;

const Heading = styled.h1`
  font-size: ${({ isHeading, theme: { fontSizes } }) =>
    isHeading ? fontSizes.large : fontSizes.small};
  color: ${({ theme: { colors } }) => colors.persianGreen};
`;

const App = () => {
  return (
    <Theme>
      <Container>
        <Heading isHeading={true}>Hello World</Heading>
        <h2>By the power of styled-components!</h2>
      </Container>
    </Theme>
  );
};
export default App;

Enter fullscreen mode Exit fullscreen mode

In the <Container> styles I opted out of destructuring in order to show that the concept of theming is possible via the props system. All we are doing is telling our props that we want to access the theme object that lives there. Inside the theme object, we can access any of the keys such as the colors object and reference a specific color (i.e persianGreen).

I personally prefer to destructure my objects such as in <Heading>, in my opinion, it looks cleaner and I prefer less repetition of long chaining.

The props object as a whole now contains two main properties, theme and isHeading, but we can add as many props as we like. A way to great leverage this, is to pass a value from state and tie the style to rendered on state change.

You can start using themes in styled-components really quick as you can see. If you need clarification on any concept from this post, don't hesitate to reach out via comments or spectrum.chat :)!

Thanks for reading!

Top comments (10)

Collapse
 
madv profile image
Amateur blogger

How would you handle responsive designs in theming?
Basically, fontSize for different layouts(mobile)?

Collapse
 
aromanarguello profile image
aromanarguello • Edited

Hey! Great question!

I usually do this by creating an object inside the theme object.

something like:

const theme = {
//..other theme objects,
fontSizes: {
  sm: 12,
  m: 14,
  l: 16,
  xl: 22
}
Enter fullscreen mode Exit fullscreen mode

Or you could put them on an array and then map them. Does this answer your question? If not would be glad to provide more examples :D

You could also name them differently based on the layout. Or create an object of layouts, with all the properties for the size inside one object.

const theme = {
//..other theme objects,
mobile: {
  fontSize: 12,
  margin: '4px',
  color: 'red',
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
madv profile image
Amateur blogger • Edited

Hey,
Thank you for your reply. I really loved your article and I am following the same approach.

However, my question is around the snippet i have attached.
Basically, in my theme i am setting common styles for my input fields which will be reused in my website.
How do i manage the commented bit?

code snippet

Thread Thread
 
aromanarguello profile image
aromanarguello • Edited

Are you trying to include in the commented part in the theme object?

@media ...// {
   fontSize: 12px
}

If so, I am not sure if this is possible, at least I can't think of a way to do it 😅 The way I would manage it would be something like this. I would create a reusable input component that I could import into my other components. Something that would look like this 👇

const Input = styled.input`
  // all your other inputFields styles
  @media (min-width: ${({
      theme: {
        breakPoints: { mobileS }
      }
    }) => mobileS}) {
    fontSize: ${({ theme: { fontSizes } }) => `${fontSizes[1]}px` }
  }
`

And in my theme object:

const theme = {
  fontSizes: [12, 14, 16, 18, 20],
  breakPoints: {
    mobileS: '320px',
    mobileM: '375px',
    mobileL: '425px'
  }
}

If you were to kebab-case your keys in the theme object, you could theoretically also be able to ...(spread) them on to your component something like: ${props => ...props}

Thread Thread
 
madv profile image
Amateur blogger

I assumed the same that there isn't a straightforward way to handle the various mobile sizes.
However, thanks for replying :)

Thread Thread
 
cesar1983 profile image
César Fernandes de Almeida

If you are still looking for something you should try github.com/morajabi/styled-media-q...

Collapse
 
thiagospart profile image
Thiago Spart

also one thing I do when using themes and I have to use it in more than one line of css i just use the css from styled-components:

import { css } from "styled-components";

export const Container = styled.div`
  ${({theme}) => css`
    font-size: ${theme.fonts.xl};
    background: ${theme.colors.gray_800};
  `};

  border-radius: 0.25rem;
`
Enter fullscreen mode Exit fullscreen mode
Collapse
 
adriangzz profile image
adriangzz

Excellent written and straight to the point, thanks!

Collapse
 
kaleidostoni profile image
PoniAlienBoi

Thanks!

Collapse
 
sharathkumar111316 profile image
sharathkumar111316

Straight to the points we required to start with theme.