React Styled Components before V4
Before talking about styled-components I need to mention a quote for every Frontend developer who doesn’t like style elements and believes that its so easy but CSS is not as EASY as you thought!
When you code CSS, you are writing abstract rules to take unknown content and organize it in an unknown medium. THAT SHIT IS HARD — keith K Grant
In the early stages, we needed a way to style our websites, so supposedly CSS was responsible for styling our websites.
But after a while, we needed to create dynamic sites. so CSS became a mess because every developer started the CSS in his/her way and there is no consistent pattern to write CSS and this caused a big issue because of their effect on the specificity of the elements and the developers had to override styles using !important
to display the UI Element as they need
but we realized that:
and these issues increase when the project grows in size, complexity, and team members.
Here are an attempts to fix these issues!
Preprocessors Appearing
Preprocessors like Sass and less are an extension of CSS that adds power and elegance to the basic language. It allows you to use variables, mixins, conditions, nesting and extends.
And we could separate CSS code to multiple files but after compilation, this CSS code will be in one global bundled file so the same issue of the overriding will still occur.
Naming Conventions Appearing
After that, Naming conventions like BEM ( Block, Element, Modifier) has appeared and it’s a CSS methodology to write CSS, so that all classes will be unique and if you need to know more about BEM you can check out my article about BEM Methodology, thus we decreased the risk of the specificity and overriding the elements styles
But there are lots of issues appeared:
- The class name is very long.
- It’s difficult to select a class name.
Now let’s talk about css-in-js role in General
CSS-in-JS has lots of benefits to use it like:
- Create unique class names to avoid the repetition of naming the class.
- Avoid specificity conflicts.
- No need to worry about how the order of files is imported.
- Linters show unused components so they can be removed if not used because we are writing JS.
- Add vendor prefixes only for the required browser.
and now there are a lot of CSS-in-JS libraries like styled-components, glamorous, emotion, radium, and styled-jss.
Now let’s talk about styled components and it’s one of the popular libraries of css-in-js.
The styled component is created by Max Stoiber to remove the mapping between components and styles.
This means that when you’re defining your styles, you’re actually creating a normal React component, that has your attached styles.
Before installing a styled component let’s install first react application then install styled components
npx create-react-app react-styled-component
For more info regarding installing your react app you can check out this link create react app
After finishing installing you should use this command to start your app
npm start
then your browser will be opened to this tab
Now you can install styled component using this command
npm install --save styled-components
Then make sure the “styled-components” plugin is added to your .babelrc
.
{
"presets": ["env", "react"],
"plugins": ["styled-components"]
}
After that we will try to convert our App.js
component to styled component
and App.js
file will looks like:
Hence let’s include styled
from styled-components
import styled from 'styled-components';
Accordingly, let’s create the wrapper for this component and use it directly instead of <div className=”App”>
then remove all styles related to this class .App
from app.css
Now let’s create Header
component instead of using header
tag in HTML5
then remove all styles related to this class .App-header
from app.css
Now let’s create HeaderImage
component instead of using img
tag
then remove all styles related to this class .App-logo
from app.css
Now let’s create Bio
and HeaderLink
components instead of using p
and a
tags
and remove all styles related to .App-link
this class from app.css
Now your components should look like itself as before.
but now we need to import keyframes
from styled-component
to remove animations styles from app.css
and add style components animations
so we will import keyframes
using this lineimport styled, { keyframes } from ‘styled-components’;
then we will create a new component for animation name
const rotate360 = keyframes`
from {
transform: rotate(0deg);
} to {
transform: rotate(360deg);
}
`;
and we will use this animation name instead of App-logo-spin
in HeaderImage
component and add the new animation name with this way
const HeaderImage = styled.img`
animation: ${rotate360} infinite 20s linear;
height: 40vmin;
`;
then we will remove all styles from app.css
and will remove the import of app.css
from app.js
file, so the file will look like
- How to use pseudo-classes like hover, focus, nth-child, first-child and so on
- Styled Components and Props
- InjectGlobal
- Attrs
- Extend
- withComponent
- Media Query
let’s update our above example with adding hover in the Header
component and when hovering on it, its background will change to be skyblue
for example
if you used one of the preprocessors before like SASS / LESS
for sure you used ampersand character (&)
so in styled components we can use some features from preprocessors like nesting
and ampersand character (&)
and in Styled Components, we used, stylis, the preprocessor that supports scss-like syntax for automatically nesting styles.
so you can just add it like:
const Header = styled.header`
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white; &:hover{
background: skyblue;
}
`;
so when hovering it will look like:
so easy right?!
Styled Components and Props
One of the great things on styled-components
is that they allow you to change styles of your components according to its props.
for example, let’s change the background-color
of the Header
if we pass primary
prop to it, so the default background-color
will be #282c34
and if primary
prop has existed the background-color
will be for example red
so now Header
component will be like <Header primary>
and component style will look like
const Header = styled.header`
background-color: ${props => props.primary ? 'red' : '#282c34'};
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
&:hover{
background: skyblue;
}
`;
so I just checked the props if there is primary prop the background-color
will be red
else the background-color
will be #282c34
and now it will look like:
so props in styled components work like Modifers
injectGlobal
NOTE
The injectGlobal API was removed and replaced by createGlobalStyle in styled-components v4.
A helper method to write global CSS. It does not return a component but adds the styles to the stylesheet directly.
we will import injectGlobal from styled components using this line
import styled, { keyframes, injectGlobal } from 'styled-components';
then we will add our global styles to the body
injectGlobal`
body{
height: 2000px;
color: #000;
margin: 0;
}
`;
Attrs
This is a method that attaches some props to a styled component and its object accepts the following values:
Prop Value: These can be of any type, except functions. They’ll stay static and will be merged into the existing component props.
Prop Factor: A function that receives the props that are passed into the component and computes a value, that is then going to be merged into the existing component props.
const Input = styled.input.attrs({
type: 'text',
size: props => (props.small ? 5 : undefined ),
placeholder: 'Enter Your Name',
})`
border-radius: 5px;
border: 3px solid blue;
display: block;
margin: 20px auto;
padding: 10px;
font-size: 15px;
color: blue;
::placeholder {
color: blue;
}
`;
and attach the component in the render method like
<Input />
<Input small />
and the output will be something like that:
Extend
This is a method that creates a new StyledComponent and extends its rules.
for example, we have 2 buttons and they have the same styles but one of them has a different border-color
const Button = styled.button`
padding: 10px
border: 3px solid black;
border-radius: 5px;
background-color: white;
display: inline-block;
margin: 0 auto 20px;
`;const GreenButton = Button.extend`
border-color: green
`;
and attach button component in render method like:
<Button>Default Button</Button>
<GreenButton>Green Button</GreenButton>
so it will look like:
withComponent
This is a method that creates a new StyledComponent with a different tag or component applied to it, but all the same rules of the one it’s called on.
we will use the prev example of Button
to use with.Component with an anchor tag
const LinkAsButton = Button.withComponent('a');
and attach it in render method like
<LinkAsButton href="https://www.google.com"> Google Website </LinkAsButton>
and it will look like
and in Styled Component V4 you can use as
attribute instead of withComponent
like:
<Button as="a">Link Button</Button>
Media Query
we will add a small media query style in the header to changebackground-color
to be black
in devices that smaller than 420px
const Header = styled.header`
background-color: ${props => props.primary ? 'red' : '#282c34'};
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
&:hover{
background: skyblue;
}
@media screen and (max-width: 420px){
background-color: black;
}
`
and it will look like: