Styling React Components: styled-components + twin.macro (Tailwind CSS 2.0)
Tags: react, styledcomponents, tailwindcss, twin
Published: 2020-12-07 18:02:17

There are lots of ways to style a react component. But there are two ways which are quite popular among React Developers.

One is the use of Utility-first CSS frameworks like `Tailwind CSS` and another one is the CSS-in-JS libraries like `styled-components` to style react components in a JS way.

But what if we will merge them both to make a powerful way to style our components? 🤔

![Interesting](https://dev-to-uploads.s3.amazonaws.com/i/gdnj7ll6mlu7ojtf7qou.gif)

Interesting, right? 🤩

So here, in this tutorial we will see, how we can use them both to style react components more efficiently.

## Before we start... 💭

**Tailwind** is a utility-first CSS framework for rapidly building custom designs, directly in the markup. It helps in building complex components from a constrained set of primitive utilities.

`twin.macro` is a library that helps to combine Tailwind CSS with libraries like `emotion` and `styled-components` to give more power to style React components.

So if you are using `styled-components` and want to power your styling with `Tailwind CSS` or you are a React beginner and want to learn a magic to style your React Components, then this article is for you.

> **Note:** _This article is based on **Tailwind CSS 2.0**. It may not work with other versions of Tailwind CSS._

## What will we build? 🤔

In this article, we will demonstrate a combination of `twin.macro` and `styled-components` to style our React Components. After this, you can easily style your React Components more efficiently for sure.

## Prerequisites 📝

-   Basic knowledge of React JS.
-   Basic knowledge of CSS.
-   Node version `v14.15.1` and npm version `6.14.8`. It may not work properly in the lower version of Node.

If you have these, Let's get started 🚀

![Let's Start](https://dev-to-uploads.s3.amazonaws.com/i/onv8vnrl1jfvxbdnei4k.gif)

## Let’s Begin 🏁

### 1. Setup our Project

#### Step - 1 : Create our app
First, Let's create our project with `create-react-app` by running:

```shell
npx create-react-app react-styling-tutorial
```

After project creation, let's open our project in VS Code (or any other Code Editor/ IDE).

#### Step - 2 : Install required dependencies
Now, let's install `twin.macro`, `tailwindcss` & `styled-components` in our project by running:

```shell
npm i --save twin.macro tailwindcss styled-components
```

Here all of my dependencies with their versions:

```json
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1",
"styled-components": "^5.2.1",
"tailwindcss": "^2.0.1",
"twin.macro": "^2.0.6",
```

> **Note**: _Please make sure to have the same version of dependencies to avoid errors._

#### Step - 3 : Configure Tailwind

After installing all the above dependencies, let's create **Tailwind config file** named `tailwind.config.js` in our `src` directory by running:

```shell
npx tailwind init src/tailwind.config.js
```

The generated file will look like below:

```jsx
module.exports = {
    purge: [],
    darkMode: false, // or 'media' or 'class'
    theme: {
        extend: {},
    },
    variants: {
        extend: {},
    },
    plugins: [],
};
```

As you can see, the config file is "empty" since there is no configuration. If you want a full version of the tailwind config, then you can run:

```shell
npx tailwind init src/tailwind.config.js --full
```

#### Step - 4 : Configure Twin

Now let's go to our `package.json` and add the following `twin` configuration:

```json
"babelMacros": {
    "twin": {
        "config": "./src/tailwind.config.js",
        "preset": "styled-components"
    }
},
```

This configuration will help to transform tailwind classes into CSS-in-JS code.

Great! Let's run our app to ensure everything is fine by running:

```shell
npm start
```
Here is what our app will look like in the browser (or similar).
![App Running success](https://i.imgur.com/IJxirFZ.png)

![Success](https://dev-to-uploads.s3.amazonaws.com/i/mppznzb6u1mdhhvhgl4m.gif)

### 2. Create Components

Okay. Let's first stop our web server.

Now remove `App.css`, `logo.svg` from the `src` directory to clean our project a little bit.

`src` directory will look like:

```
.
|____App.js
|____App.test.js
|____index.css
|____index.js
|____tailwind.config.js
|____reportWebVitals.js
|____setupTests.js
```

Now let's modify `App.js` as below:

```jsx
import React from 'react';

const App = () => {
    return <h1>My App Component</h1>;
};

export default App;
```

Now if you will run the app again, it will work absolutely fine with no errors 😎

![App Component](https://dev-to-uploads.s3.amazonaws.com/i/inaf6vs3xl8qtrrk2ap6.png)

![Working fine](https://dev-to-uploads.s3.amazonaws.com/i/942z8azch6y9ugkwa3k4.gif)

Great. Next, create a directory, named `components` inside the `src` directory.

And inside the `components` directory let's create another directory named `Button`.
Now inside our `Button` directory, create an `index.js` file.

`src` directory will look like:

```
.
|____components
| |____Button
| | |____index.js
|____App.js
|____App.test.js
|____index.css
|____index.js
|____tailwind.config.js
|____reportWebVitals.js
|____setupTests.js
```

Next, inside the `src/components/Button/index.js` let's write our `button` component as below:

```jsx
import React from 'react';

const ButtonComponent = () => {
    return <button>Click Me!</button>;
};

export default ButtonComponent;
```

Now, let's come back to `src/App.js` and import our `ButtonComponent`

```jsx
import React from 'react';
import ButtonComponent from './components/Button'; // new

const App = () => {
    return (
        // new
        <div> 
            <ButtonComponent />
        </div>
    );
};

export default App;
```

Here is what our app will look like in the browser.

![Showing Button Component](https://dev-to-uploads.s3.amazonaws.com/i/m22o6580sw9rbmw0xr1n.png)

You can see our button component is here  🤩

![Great](https://dev-to-uploads.s3.amazonaws.com/i/dr24omjxfcp9mthsoyty.gif)


### 3. Setup Theme

Okay. We are doing great so far. Now let's set up our theme for our project.

Let's stop our server and goto `/src/index.css` and put the following css at the top:

```css
:root {
    --color-primary: #4ff0c9;
    --color-secondary: #172a45;
    --color-white-alt: #ccd6f6;
}
```

Here we have created 3 variables to store colors, named `--color-primary`, `--color-secondary`, and `--color-white-alt`.

Now add our colors inside the `theme` in `/src/tailwind.config.js` like below:

```jsx
module.exports = {
    purge: [],
    darkMode: false,
    theme: {
        extend: {
            colors: { // new
                primary: 'var(--color-primary)', // new
                secondary: 'var(--color-secondary)', // new
                whiteAlt: 'var(--color-white-alt)', // new
            }, // new
        },
    },
    variants: {
        extend: {},
    },
    plugins: [],
};
```

Great!!! Let's first run our app and check, everything is fine or not.

![Showing Button Component](https://dev-to-uploads.s3.amazonaws.com/i/m22o6580sw9rbmw0xr1n.png)

We got the same result as before 🤟

### 4. Style Components

Let's create a `styles` directory inside our `src` directory and create a file named `StyledApp.js` inside the `styles` directory for styling our `App` component.

Finally, our `src` directory will look like:

```
.
|____components
| |____Button
| | |____index.js
|____styles
| |____StyledApp.js
|____App.js
|____App.test.js
|____index.css
|____index.js
|____tailwind.config.js
|____reportWebVitals.js
|____setupTests.js
```

Now, open the `StyledApp.js` and let's write some styling for our `App` component.

```jsx
import tw, { styled } from 'twin.macro';

export const StyledApp = styled.div`
    ${tw`flex justify-center items-center h-screen`}
`;
```

Next, come back to `App.js` and import our `StyledApp` as below:

```jsx
import React from 'react';
import ButtonComponent from './components/Button';
import { StyledApp } from './styles/StyledApp'; // new

const App = () => {
    return (
        <StyledApp> {/* new */}
            <ButtonComponent />
        </StyledApp>
    );
};

export default App;
```

Now save and look at your browser, the button comes to the center of the screen.

![StyledApp](https://dev-to-uploads.s3.amazonaws.com/i/j0xaee76gm3o4qbpon82.png)

Taddddda!!! As you can see, our styling for our `App` component is working perfectly 😎

![Wow](https://dev-to-uploads.s3.amazonaws.com/i/z67yl0deziuywcice1nz.gif)

We can also use `GlobalStyles` in our `App` component as below:

```jsx
import React from 'react';
import ButtonComponent from './components/Button';
import { GlobalStyles } from 'twin.macro'; // new
import { StyledApp } from './styles/StyledApp';

const App = () => {
    return (
        <div>
            <GlobalStyles /> {/* new */}
            <StyledApp>
                <ButtonComponent />
            </StyledApp>
        </div>
    );
};

export default App;

```

Now our app will look like:

![GlobalStyles Applied](https://dev-to-uploads.s3.amazonaws.com/i/auw7n118vkbq3re62vt8.png)

You can see, the style of our Button component is changed because of the `GlobalStyles`.

![Wow](https://dev-to-uploads.s3.amazonaws.com/i/gxg8rmjiuk8u20gkltg4.gif)

Amazing! Now let's style our `ButtonComponent`. Create another file named `StyledButton.js` inside `/src/styles`.

`src/styles` directory will look like:

```
.
|____StyledApp.js
|____StyledButton.js
```

Write some styling inside our `StyledButton.js` for our button component.

```jsx
import tw, { styled } from 'twin.macro';

export const StyledButton = styled.button`
    ${tw`py-3 px-8 uppercase rounded border border-primary hover:bg-primary`}
`;
```

Next, go back to `/src/components/Button/index.js` and import our `StyledButton` as below:

```jsx
import React from 'react';
import { StyledButton } from '../../styles/StyledButton'; // new

const ButtonComponent = () => {
    return <StyledButton>Click Me!</StyledButton>; // new
};

export default ButtonComponent;
```

Now you can see our Styled Button in our browser.

![StyledButton](https://i.imgur.com/rzgUaVO.gif)

![Working](https://dev-to-uploads.s3.amazonaws.com/i/zzbuw7u8gypvaun60eeg.gif)

Now here if you want to add your custom CSS for `ButtonComponent` you can do that inside `/src/styles/StyledButton.js` as below :

```jsx
import tw, { styled } from 'twin.macro';

export const StyledButton = styled.button`
    ${tw`py-3 px-8 uppercase rounded border border-primary hover:bg-primary duration-200`}; // added duration-200 (optional)

    & {
        background-color: yellow;
    }

    &:hover {
        font-size: 2rem;
    }
`;
```

![Custom style](https://i.imgur.com/qAnvYDG.gif)

We can also access `theme` data directly like below:

```jsx
import tw, { styled, theme } from 'twin.macro'; // new

export const StyledButton = styled.button`
    ${tw`py-3 px-8 uppercase rounded border border-primary hover:bg-primary duration-200`}; // added duration-200 (optional)

    & {
        background-color: ${theme`colors.whiteAlt`}; // modified
    }

    &:hover {
        font-size: 2rem;
    }
`;
```

Now you can see the background color of the button is changed.

![Theme data](https://i.imgur.com/nbxsddO.gif)


### 4. Conditional Styling

Let's change our styling with conditions.

To do that, let's change our `StyledButton.js` as below:

```jsx
import tw, { styled, theme, css } from 'twin.macro'; // modified

export const StyledButton = styled.button(() => [
    tw`py-3 px-8 uppercase rounded border border-primary hover:bg-primary duration-200`,

    css`
        & {
            background-color: ${theme`colors.whiteAlt`};
        }

        &:hover {
            font-size: 2rem;
        }
    `,
]);
```

It will give us the same output as before 🤟

Okay. Let's add a condition.
We will style our button differently if `isSecondary` is true.

Here is our final code will look like:

```jsx
import tw, { styled, theme, css } from 'twin.macro';

export const StyledButton = styled.button(({ isSecondary }) => [
    // updated
    tw`py-3 px-8 uppercase rounded border border-primary hover:bg-primary duration-200`,

    css`
        & {
            background-color: ${theme`colors.whiteAlt`};
        }

        &:hover {
            font-size: 2rem;
        }
    `,

    isSecondary && tw`border-secondary hover:bg-secondary hover:text-white`, // new
]);
```

Now let's go back to `ButtonComponent` in `src/components/Button/index.js` and pass the `isSecondary` parameter in `StyledButton` like below:

```jsx
const ButtonComponent = () => {
    return <StyledButton isSecondary>Click Me!</StyledButton>; // modified
};

export default ButtonComponent;
```

![Conditional Component](https://dev-to-uploads.s3.amazonaws.com/i/9suhym4cyt98ws1in67l.gif)

Awwwwwesome! Isn't it? 😎

<!-- ![Wow](https://dev-to-uploads.s3.amazonaws.com/i/uh2z9zgyubiiwhs06uop.gif) -->

## Conclusion 📋

Here is my Github repo for your reference - https://github.com/devsmranjan/react-tailwindcss-styledcomponents-template

You can use this as a template for your next project 🙂

Thank you for reading my article 🙂 . I hope you have learned something here.

Happy coding 👨‍💻👩‍💻 and stay tuned for my next post.

Thanks! Don't forget to give a ♥️ and follow :)