DEV Community

Smruti Ranjan Rana
Smruti Ranjan Rana

Posted on • Edited on

Styling React Components: styled-components + twin.macro (Tailwind CSS 2.0)

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

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

Let’s Begin 🏁

1. Setup our Project

Step - 1 : Create our app

First, Let's create our project with create-react-app by running:

npx create-react-app react-styling-tutorial
Enter fullscreen mode Exit fullscreen mode

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:

npm i --save twin.macro tailwindcss styled-components
Enter fullscreen mode Exit fullscreen mode

Here all of my dependencies with their versions:

"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",
Enter fullscreen mode Exit fullscreen mode

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:

npx tailwind init src/tailwind.config.js
Enter fullscreen mode Exit fullscreen mode

The generated file will look like below:

module.exports = {
    purge: [],
    darkMode: false, // or 'media' or 'class'
    theme: {
        extend: {},
    },
    variants: {
        extend: {},
    },
    plugins: [],
};
Enter fullscreen mode Exit fullscreen mode

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:

npx tailwind init src/tailwind.config.js --full
Enter fullscreen mode Exit fullscreen mode

Step - 4 : Configure Twin

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

"babelMacros": {
    "twin": {
        "config": "./src/tailwind.config.js",
        "preset": "styled-components"
    }
},
Enter fullscreen mode Exit fullscreen mode

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:

npm start
Enter fullscreen mode Exit fullscreen mode

Here is what our app will look like in the browser (or similar).
App Running success

Success

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
Enter fullscreen mode Exit fullscreen mode

Now let's modify App.js as below:

import React from 'react';

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

export default App;
Enter fullscreen mode Exit fullscreen mode

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

App Component

Working fine

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
Enter fullscreen mode Exit fullscreen mode

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

import React from 'react';

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

export default ButtonComponent;
Enter fullscreen mode Exit fullscreen mode

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

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

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

export default App;
Enter fullscreen mode Exit fullscreen mode

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

Showing Button Component

You can see our button component is here 🀩

Great

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:

:root {
    --color-primary: #4ff0c9;
    --color-secondary: #172a45;
    --color-white-alt: #ccd6f6;
}
Enter fullscreen mode Exit fullscreen mode

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:

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: [],
};
Enter fullscreen mode Exit fullscreen mode

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

Showing Button Component

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
Enter fullscreen mode Exit fullscreen mode

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

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

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

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

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;
Enter fullscreen mode Exit fullscreen mode

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

StyledApp

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

Wow

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

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;

Enter fullscreen mode Exit fullscreen mode

Now our app will look like:

GlobalStyles Applied

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

Wow

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
Enter fullscreen mode Exit fullscreen mode

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

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

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

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

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

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

export default ButtonComponent;
Enter fullscreen mode Exit fullscreen mode

Now you can see our Styled Button in our browser.

StyledButton

Working

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

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;
    }
`;
Enter fullscreen mode Exit fullscreen mode

Custom style

We can also access theme data directly like below:

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;
    }
`;
Enter fullscreen mode Exit fullscreen mode

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

Theme data

4. Conditional Styling

Let's change our styling with conditions.

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

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;
        }
    `,
]);
Enter fullscreen mode Exit fullscreen mode

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:

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
]);
Enter fullscreen mode Exit fullscreen mode

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

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

export default ButtonComponent;
Enter fullscreen mode Exit fullscreen mode

Conditional Component

Awwwwwesome! Isn't it? 😎

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 :)

Top comments (9)

Collapse
 
angelmtztrc profile image
Angel Martinez

Nice post, actually you don't need to "compile" tailwindcss as twin.macro does it behind the scenes.

The only thing you need in your project is twin.macro and styled-components

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
devsmranjan profile image
Smruti Ranjan Rana

Thanks for appreciating this post.
I'll surely improve this article in the next few days.

Collapse
 
arcbjorn profile image
Arc

I just finished the project where I integrated tailwindcss into Svelte.

Recently I was debating whether to use Material UI React kit vs integrating tailwindcss in React in my new project. You are spot on! Now I'm definitely trying your approach.

Great job, brother πŸ€“

Collapse
 
yukoliesh profile image
yukoliesh

I landed here after I found out that TailwindCSS could be messy and thought if I could use this with Styled Component. Great article to make me understand how to use both together with simplicity! Thanks for sharing!

Collapse
 
guerrillacoder profile image
GuerrillaCoder • Edited

What does <GlobalStyles /> do?

Collapse
 
devsmranjan profile image
Smruti Ranjan Rana

Basically, <GlobalStyles /> provides a base style to our app.

Twin uses the same preflight base styles as Tailwind to smooth over cross-browser inconsistencies.

The GlobalStyles import adds these base styles along with some @keyframes for the animation classes and some global css that makes the ring classes and box-shadows work.

Collapse
 
senninseyi profile image
Senninseyi

Same thought too

Collapse
 
ik01 profile image
IshaqKam

What is the purpose of tailwing.config.js file?