Everything you need to know about Styled Components
Tags: react
Published: 2021-05-04 00:12:08

When I started learning CSS, it seems pretty straightforward to play with some selectors and apply styles to any elements but as bigger, as my projects get, my style sheets look more chaotic and you've probably experienced it for yourself. At some point, it gets hard to figure out a good way to organize your styles.

Then you probably jump to use some preprocessors like SASS, LESS which add a lot of useful features but they don't do much to control CSS specificity unless you start using some methodologies like BEM (Block, Element, Modifier) which allows reuse of existing code without duplications and divide UI into independent blocks.

After a couple of years, a new paradigm of CSS-in-JS appears and tries to solve these problems to construct and manage our styles in a component-specific manner to allows us to create custom, exportable components.

One of them is Styled Components, it provides us many cool features to style our React components.

- It generates unique class names for your styles which means that you won't have any issues with duplication, overlap, or misspellings.
- You can adapt styles of a component based on its props which makes dynamic styling.
- Easier to maintain styles no matter how big is your application while still writing CSS you know

Styled components are available both for React and React Native

## Installation

You can install it running a single command and you're ready to roll:

```bash
npm install --save styled-components
```

## Getting Started

### Style an HTML element

We are going to create a Title component based in an HTML element like `h1` to give some styles like giving a purple color and align it to center to use is it in Blog Page.

```jsx
import styled from 'styled-components'
import * as React from 'react'

const Title = styled.h1`
	color: purple;
	text-align: center;
`

const BlogPage = () => {
	return(
		<div>
			<Title> Personal Blog </Title>
			...
		</div>
	)
}

export default BlogPage;
```

### Style a React Component

What if we already have a set of custom React components and we want to extend styles? It's almost similar, when you want to style an HTML element, you put a dot. If you want to style the components, you put parentheses and pass the actual component. In this case, we are gonna style a button from `material-ui` and adjust his size with css.

```jsx
import Button from '@material-ui/core/Button';

const FullWidthButton = styled(Button)`
	width: 300px;
`
```

Keep in mind that you can style pseudo-selectors and classes inside of the styled component if needed. 

```jsx
const Button = styled.button`
	...

	:hover {
		color: blue;
	}

	::before {
		content: ' ';
		...
	}
`
```

Note: Styled components works with Tagged template literal under the hood. If you don't know much about it, you can find more info here [FreeCodeCamp](https://www.freecodecamp.org/news/a-quick-introduction-to-tagged-template-literals-2a07fd54bc1d/). 

### Creating Global Styles

To give global style, we need to use `createGlobalStyle` and create a constant from it and anything inside of here will be styled in our entire application. This will be a component that needs to be called at the Root component and make sure it starts with an uppercase.

```jsx
import {createGlobalStyle} from 'styled-component'

const GlobalStyles = createGlobalStyle`
	body {
		font-family: Roboto;
	}
`

export default function App(){
	return(
		<>
			<GlobalStyles/>
			...
		</>
	)
}
```

### Adjust Style based on props

We can set dynamic styles according to props that can be either `true` or `false` based on conditionals.

A simple case would be to give some styles to stand out recent blog posts we published from all the list. I'm gonna give a gradient color to the background of card.

```jsx
const BlogCard = styled(Card)`
	...
	${props => 
			props.isNewPost &&
			`
				background: linear-gradient(to right, red, orange);
			`
		}
`

export default function BlogList(){
	return(
		<>
			<BlogCard 
				isNewPost
				title="Everything you need to know about Styled Components"
				...
			/>
			<BlogCard 
				title="Learning Tips from my experience as developer"
				...
			/>
		</>
	)
}
```

### Style a component based on complex props

In some scenarios, we will have a prop that can be a string and not only a boolean value which means we will have more conditionals. 

Eg. I have a list of blog post cards and I would love to change the color of its category according to its value. If it's `personal` we'll set it to purple color, if it's `react` should be orange and if it's `git` let's change it to red.

```jsx
const CategoryName = styled.span`
	font-size: 0.875rem;
	color: ${({ topic }) => {
		if(topic === 'personal') return 'purple';
		if(topic === 'react') return 'blue';
		if(topic === 'git') return 'red';
		return 'black'
	}}
`

export default function BlogCard(){
	return(
		<Card>
			...
			<CategoryName category={category}>{category}</CategoryName>
			...
		</Card>
	)
}
```


### Animations

To create animations in styled components, we need to import `keyframes` and start writing our css animation code. Then we need to reuse that variable where we needed.

In this case, we'll animate the position of an `h1` to go from left ro right. 

```jsx
import {keyframes} from 'styled-components'

const move = keyframes`
	from {
		transform: translateX(0);
	}
	to {
		transform: translateX(100%)
	}
`

const Heading = styled.h1`
	animation: ${move} 2s ease infinite;
`
```

### Create and use a Theme

To ingrate a theme on our application, we need to use the `ThemeProvider`  and pass an object to it's `theme` prop. We will use this theme to set colors and fonts.

```jsx
import {ThemeProvider} from 'styled-components'

// create Theme object
const theme = {
	colors: {
		purple: "#123123",
		blue: "#2563eb"
	},
	fonts: {
		heading: "Roboto, sans-serif",
		body: "Montserrat"
	}
}

// how to use it in a styled component
const Heading = styled.h1`
	text-align: center;
	color: ${props => props.theme.colors.purple}
	font-family: ${({ theme }) => theme.fonts.body} // destructuring props
`

// Call ThemeProvider in your Root Component
export default function App(){
	return(
		<ThemeProvider theme={theme}>
			<Heading>Hello its from the theme</Heading>
		</ThemeProvider>
	)
}
```

### Using `css` prop to define styles

Sometimes we don't want to create an extra component to just apply a bit of styling and there it comes `css` prop. It works on HTML tags as well as components and supports everything styled components support including props, theme and custom components.

To enable support for the css prop you have to use a babel plugin or macro.

**Usage with the [babel plugin](https://styled-components.com/docs/tooling#babel-plugin)**

```jsx
// Babel plugin does that automatically!

// HTML element
<div
  css={`
    background: papayawhip;
    color: ${props => props.theme.colors.text};
  `}
/>

// Custom component
<Title
  css="padding: 0.5em 1em;"
/>
```

**Usage with Babel macro**

```jsx
// You need to import it manually
import styled from 'styled-components/macro'

// Custom component
<div
  css={`
    background: papayawhip;
    color: ${props => props.theme.colors.text};
  `}
/>
```

Note that Babel plugin or macro turns any elements with a css prop into a styled components.

### Using `as` prop to reassign the HTML tag

In some instances, we want to keep all styling we've applied to a component but just change what element/component is rendering. 

I usually use it when it comes about anchor tags and buttons. We don't need to rewrite the css rules and create a component for our anchor tag when it has the same look and feel with our buttons. Instead, we can use `as` and then pass the attributes the anchor needs.

```jsx
const Button = styled.button`
	...
`

<Button as="a" href="https://www.google.com.pe"> Go to Google.com </Button>
```

### Using `attrs` method to add HTML attributes

It allows us to change and add attributes to our styled elements. The `attrs` object accepts either any type of attributes that belongs to HTML tags or a function that receives props to finally merged them into existing component props.

```jsx

// In this case, type `button` is going to override whatever is in component
const Button = styled.button.attrs({
	type: "button"
})`
	display: inline-block;
	...
`

// We can use props
const Button = styled.button.attrs(props => ({
	type: props.type || "button"
}))`
	display: inline-block;
	...
`

<Button type="submit">Submit</Button>
```

### Use Styled Components with the Object Syntax

There is also another way that we can style components, we can use object-based styling. Let's see how different that is. At the end, both ways do exactly the same thing and they are just different ways of writing styled components

```jsx
const Title = styled.h1(props => ({
	color: red,
	fontSize: props.small ? 16 : 24,  // by default its pixel
	fontFamily: 'sans-serif',
}))
```

## Final Notes

As you can see, it's actually pretty easy to understand and start using styled-components in your React applications. There are cool features that can help us to custom our component the way we want, make some dynamic styling using props, creating a theme and so on. So I would encourage you to dive into [the documentation](https://github.com/styled-components/styled-components) and try it out on your projects. 

Here are a few miscellaneous link related that help me to understand more about styled components 

- [Build your own styled-components library](https://blog.logrocket.com/build-your-own-styled-components-library/)
- [A quick introduction to Tagged Template Literals](https://www.freecodecamp.org/news/a-quick-introduction-to-tagged-template-literals-2a07fd54bc1d/)
- [Enabling support for the css prop in Styled components](https://medium.com/styled-components/announcing-native-support-for-the-css-prop-in-styled-components-245ca5252feb)

Hope you enjoyed it. Thanks for reading! 

... As always, enjoy your own process of learning 🚀

Feel free to [reach out](https://paulccari.com) if you wanna chat about anything.