💅 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.
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
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:
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 />
:
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:
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.
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.
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.
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>
);
}
}
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:
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.
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.
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.