Tutorial

Theming styled-components

Published on March 9, 2018
Default avatar

By Flavio Copes

Theming styled-components

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

💅 styled-components are a great way to handle CSS in React. If you’re new to styled-components check out our article styled-components, the Modern Way to Handle CSS in React for an introduction.

In this post we’re going to create a simple email newsletter subscription form and use styled-components to handle the visual appearance.

Setup using React Boilerplate

We’ll start with setting up a React Boilerplate application. If you prefer however, you can also use Create React App to get started.

Check out https://www.reactboilerplate.com/ for a detailed explanation of this boilerplate.

To create a new project we just clone the boilerplate GitHub repository:

$ git clone --depth=1 https://github.com/react-boilerplate/react-boilerplate.git

And we remove the example app to start from a clean slate and then start the app:

$ npm run clean
$ npm start

Writing a Sample Form

Now let’s build the email signup form. We create a signup form in its own component, using styled-components to render it nicely.

Let’s create four styled-components: Form, Title, Button and Input.

Each component represents a small portion of our form, and we add a few CSS rules for each one:

components/SignupForm/index.js
import React from 'react';
import styled from 'styled-components';

const Form = styled.form`
  margin: 0 auto;
  width: 50%;
  min-width: 400px;
  max-width: 800px;
  text-align: center;
  border: 1px solid #ddd;
  padding-top: 0px;
  padding-bottom: 90px;
  color: black;
  background: white;
`;

const Title = styled.h2`
  margin-top: 40px;
  margin-bottom: 70px;
  font-size: 1.5em;
  color: black;
  background-color: white;
`;

const Button = styled.button`
  font-size: 1.5em;
  background-color: black;
  color: white;
`;

const Input = styled.input`
  font-size: 1.45em;
  border: 1px solid #ddd;
`;

Then we create a simple component that handles the submit event with a simple console.log() that prints out the given email, as we just want to focus on the styling part:

import React from 'react';

export default class SignupForm extends React.Component {

  signUp = (e) => {
    const email = new FormData(e.target).get('email');
    e.preventDefault();
    console.log(`New signup from ${email}`);
  }

  render() {
    return (
      <Form onSubmit={this.signUp}>
        <Title>
          Sign up to my newsletter
        </Title>
        <Input type="email" name="email" />
        <Button>Sign up</Button>
      </Form>
    );
  }
}

Next, we just import it in the HomePage component that React Boilerplate created for us, and we render <SignupForm />:

containers/HomePage/index.js
import React from 'react';
import SignupForm from '../../components/SignupForm';

export default class HomePage extends React.Component {
  render() {
    return (
      <SignupForm />
    );
  }
}

That’s it, the form should now display nicely in our application:

Single component using styled-components

In the CSS we have a few different properties that are used by different components: the background and foreground colors, the border color and the text color.

They now have fixed colors because we had the form on just one page, but the requirements changed and now we are told the form must be added to a variety of pages with different backgrounds and color schemes.

We need to make the component reusable, and we can do so using a theme.

Creating a Theme

A theme is created by wrapping all our components in a ThemeProvider wrapper component, and by referencing the properties of props.theme in our styled-components CSS:

import React from 'react';
import styled, { ThemeProvider } from 'styled-components';

const Form = styled.form`
  /* other properties */
  border: 1px solid ${(props) => props.theme.borderColor};
  color: ${(props) => props.theme.primaryColor};
  background-color: ${(props) => props.theme.secondaryColor};
`;

const Title = styled.h2`
  /* other properties */
  background-color: ${(props) => props.theme.secondaryColor};
  color: ${(props) => props.theme.primaryColor};
`;

const Button = styled.button`
  /* other properties */
  background-color: ${(props) => props.theme.primaryColor};
  color: ${(props) => props.theme.secondaryColor};
`;

const Input = styled.input`
  /* other properties */
  border: 1px solid ${(props) => props.theme.borderColor};
`;

We create a theme object, which is an object literal with the properties we reference in our styled-components:

const theme = {
  secondaryColor: 'white',
  primaryColor: 'black',
  borderColor: '#ccc',
};

and finally we wrap the Form component in a ThemeProvider wrapper component:

export default class SignupForm extends React.Component {

  /* ... */

  render() {
    return (
      <ThemeProvider theme={theme}>
        <Form onSubmit={this.signUp}>
          <Title>
            Sign up to my newsletter
          </Title>
          <Input type="email" name="email" />
          <Button>Sign up</Button>
        </Form>
      </ThemeProvider>
    );
  }
}

This is the basic method for theming using styled-components. We put all the theme styles in the theme object and all components use those styles.

Creating Reusable Themes

We will now add the signup form twice to a page. The first time the background of the page is bright, and the second time it’s dark.

We do so with some simple CSS rules added to app/global-styles.css, a file included automatically by React Boilerplate:

.container.dark {
  background: #282828;
}

We can wrap the SignupForm components in a class that uses the container class, and the presence of a dark class will make it dark.

containers/HomePage/index.js
import React from 'react';
import SignupForm from '../../components/SignupForm';

export default class HomePage extends React.Component {
  render() {
    return (
      <main>
        <div className="container">
          <SignupForm />
        </div>
        <div className="container dark">
          <SignupForm />
        </div>
      </main>
    );
  }
}

Two components render with the same style on different backgrounds

What if we want the second form to blend nicely in the dark background, and not stand out like a sore thumb? We add a dark prop on SignupForm in the HomePage component’s render() method:

return (
  <main>
    <div className="container bright">
      <SignupForm />
    </div>
    <div className="container dark">
      <SignupForm dark />
    </div>
  </main>
);

And we look for the prop it in the SignupForm component’s constructor() method, and, if present, we use a dark theme:

export default class SignupForm extends React.Component {

  constructor(props) {
    super(props);

    this.theme = {
      secondaryColor: 'white',
      primaryColor: '#282828',
      borderColor: '#ccc',
    };

    if (props.dark) {
      this.theme.secondaryColor = '#282828';
      this.theme.primaryColor = '#fff';
    }
  }

  /* ... */

  render() {
    return (
      <ThemeProvider theme={this.theme}>
        <Form onSubmit={this.signUp}>
          <Title>
            Sign up to my newsletter
          </Title>
          <Input type="email" name="email" />
          <Button>Sign up</Button>
        </Form>
      </ThemeProvider>
    );
  }
}

We now have the result we wanted, fitting more nicely into the dark background:

The final result of our theming, the component with multiple themes


This method allows us to play with different presentations by creating a convention of properties, and by editing the theme based on the style we need.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Flavio Copes

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
1 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

I find the use of the boilerplate to add a lot of overhead. I.e., more to think about. Although the article mentions Create React App it doesn’t say what packages to add to CRA nor how to structure the project files so I didn’t give that a try.

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel