DEV Community

Cover image for How to Style Your React Apps with Less Code Using Tailwind CSS, Styled Components, and Twin Macro
Ibrahima Ndaw
Ibrahima Ndaw

Posted on • Edited on • Originally published at ibrahima-ndaw.com

How to Style Your React Apps with Less Code Using Tailwind CSS, Styled Components, and Twin Macro

Tailwind is a utility-first CSS framework for rapidly building custom designs. It can be used alone to style React Apps. However, it can be better combined with Styled Components. That combination brings the magic of Tailwind into CSS-in-JS.

In this guide, we will build a form component without writing a single line of CSS using Tailwind CSS, Styled Components, and Twin Macro.

Let's dive in!

Why use it?

The "Why" is pretty legit and important, since we can use either Tailwind CSS or Styled Components. So why combine them and use both at the same time?
Well, Tailwind classes can be quite long, and it causes our components to have some readability issues. Maintaining them can be tough.

In the case of Styled Components, there is no problem except the fact that we have to write the style. It is not that problematic – but why should we write something that Tailwind already offers?

So it makes sense to use Tailwind CSS in combination with Styled Components. Tailwind CSS helps with utility classes, and Styled Components keeps our components clean with the help of CSS-in-JS.

Setting up

In this guide, we will build a simple form as an example. And to do so, we need a fresh React app.
So, let's run in the terminal the following command.

    npx create-react-app react-styled-tailwind
Enter fullscreen mode Exit fullscreen mode

Next, structure your folder as follows:

├── src
|  ├── App.js
|  ├── App.test.js
|  ├── assets
|  |  └── tailwind.css
|  ├── index.js
|  ├── serviceWorker.js
|  ├── setupTests.js
|  ├── tailwind.config.js
|  └── styles
|     └── index.js
├── babel.plugin.js
├── package.json
├── postcss.config.js
├── README.md
├── yarn-error.log
└── yarn.lock
Enter fullscreen mode Exit fullscreen mode

I will explain each file as we progress, but for now, let's install the dependencies.

    yarn add -D tailwindcss twin.macro autoprefixer babel-plugin-macros postcss-cli
Enter fullscreen mode Exit fullscreen mode

Next, install Styled Components by running this command.

    yarn add styled-components
Enter fullscreen mode Exit fullscreen mode

Once these libraries are installed, we can now move to the configuration of Tailwind CSS

Configuring Tailwind CSS

To configure it, we have to manually add a config file or run the following command to generate a new one:

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

Here, instead of generating the config file on the root directory, you have to put it in the src folder - otherwise an error will be thrown by Twin Macro.

And the generated file will look like this.

  • tailwind.config.js
module.exports = {
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the config file is "empty" since there is no configuration. For this tutorial, we don't need to configure anything here. But you can customize it to follow your needs or run the command with the --full option to get the complete Tailwind config.

Next, we need to create a new file postcss.config.js in the root directory.

  • postcss.config.js
module.exports = {
  plugins: [
    require("tailwindcss")("./src/tailwind.config.js"),
    require("autoprefixer"),
  ],
}
Enter fullscreen mode Exit fullscreen mode

This configuration tells the postcss.config.js file to use the Tailwind CSS library and the tailwind.config.js file during compile-time. With the help of autoprefixer it tracks which properties need to be prefixed.

With that setup, we can now move to the babel.plugin.js file which helps to transform Tailwind classes into CSS-in-JS code.

  • babel.plugin.js
module.exports = {
  tailwind: {
    plugins: ["macros"],
    config: "./src/tailwind.config.js",
    format: "auto",
  },
}
Enter fullscreen mode Exit fullscreen mode

Later we will see in action what this file does. But for now, just keep in mind that it's the glue between Tailwind CSS and Styled Components.

There are just three last steps to do to complete the setup.

still

First, in the tailwind.css file, we need to import some utilities from the Tailwind library.

  • src/assets/tailwind.css
@tailwind base;

@tailwind components;

@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Here, as you can see, there is nothing fancy, just some imports that allow us to use Tailwind utility classes.

The second step is to connect our React App with Tailwind CSS.

  • index.js
import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
import "./assets/styles.css"
import * as serviceWorker from "./serviceWorker"

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
)

serviceWorker.unregister()
Enter fullscreen mode Exit fullscreen mode

Here, we import assets/styles.css which contains the CSS style. And later, we will tweak the default script a bit to build the CSS and add it to the assets/styles.css file during compile-time.

And last but not the least, we have to update the package.json file.

  • package.json
"scripts": {
    "build:css": "postcss src/assets/tailwind.css -o src/assets/styles.css",
    "watch:css": "postcss src/assets/tailwind.css -o src/assets/styles.css",
    "start": "npm run watch:css & react-scripts start",
    "build": "npm run build:css react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
 }
Enter fullscreen mode Exit fullscreen mode

These two scripts build:css and watch:css will respectively build the CSS and watch for changes and rebuild it if needed. And as I said earlier, the output file will be located in the assets folder.

With that change, we can now use Tailwind in our app. Let's now combine it with Styled Components.

Tailwind CSS + Styled Components

Earlier, in our structure folder, we had a styles folder. It's time to tweak it with the following code.

  • styles/index.js
import styled from "styled-components"
import tw from "twin.macro"

const StyledForm = styled.main.attrs({
  className: "flex flex-col h-screen justify-center items-center bg-gray-100",
})`
  & {
    form {
      ${tw`bg-white text-center rounded py-8 px-5 shadow max-w-xs`}
    }
    input {
      ${tw`border-gray-300 mb-4 w-full border-solid border rounded py-2 px-4`}
    }
    button {
      ${tw`bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 border border-blue-700 rounded`}
    }
  }
`
export default StyledForm
Enter fullscreen mode Exit fullscreen mode

We start by importing tw which allows us to use Tailwind classes in nested properties. It's perfectly fine to use the utility classes with the className attribute, but if you want to nest properties you have to use the twin.macro library.

This library will use the babel plugin macros config (babel.plugin.js) to transform the Tailwind CSS utility classes used by nested selectors into readable code that Styled Components can understand.

You can see in this example below how the transformation is done.

// input
const test = ${tw`text-center bg-red w-full`}
// output
const test = {
    background: 'red',
    textAlign: 'center',
    width: '100%'
}
Enter fullscreen mode Exit fullscreen mode

Great! Now that we have combined Tailwind with Styled Components, let's add the styled component to the App.js file.

  • App.js
import React from "react"
import StyledForm from "./styles"

function App() {
  return (
    <StyledForm>
      <form>
        <input type="text" placeholder="Full name" />
        <input type="text" placeholder="Email" />
        <input type="text" placeholder="Password" />
        <button>Sign In</button>
      </form>
    </StyledForm>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Here, we just imported the styled component and wrapped everything with it to make our form look nice.

illustration

Great! You can already see how powerful this combination is. We have built a form component without writing a line of CSS and the component is still readable.

Conclusion

There is a bit of hassle to set up Tailwind CSS. But once it's done and combined with CSS-in-JS, it's really powerful and flexible. This is partly because we can customize the tailwind.config.js file to follow our need or just write normal CSS as we usually do with Styled Components. It's definitely something to consider in your next React app.

Thanks for reading!

You can find the Source Code here

Resources

Tailwind CSS Docs

Tailwind CSS Cheat sheet

Twin Macro Docs

Styled Components Docs

Top comments (7)

Collapse
 
codypearce profile image
Cody Pearce
const StyledForm = styled.main.attrs({
  className: "flex flex-col h-screen justify-center items-center bg-gray-100",
})`
  & {
    form {
      ${tw`bg-white text-center rounded py-8 px-5 shadow max-w-xs`}
    }
    input {
      ${tw`border-gray-300 mb-4 w-full border-solid border rounded py-2 px-4`}
    }
    button {
      ${tw`bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 border border-blue-700 rounded`}
    }
  }
`

I haven't really done much Tailwind with Styled Components, but this looks kind of difficult to maintain, have you found that to be the case or is it easier than it looks?

Collapse
 
ibrahima92 profile image
Ibrahima Ndaw

The list to style an element can be huge but isolated it in the Styled Components is much better. And it's definitely more maintainable than use it directly in the component itself.

Collapse
 
abhishekpurecode profile image
abhishek • Edited

Styling React apps becomes more efficient by combining Tailwind CSS, Styled Components, and Twin Macro. Integrate Tailwind for utility-first styling, offering an extensive set of pre-built classes. Styled Components bring the power of CSS-in-JS, allowing for dynamic styling in React components. Twin Macro acts as a bridge, enabling the seamless use of Tailwind CSS within Styled Components, resulting in cleaner and more concise code. This approach maximizes the benefits of each tool, empowering developers to create visually appealing React applications with minimal code, improved maintainability, and a flexible styling ecosystem.

To know more, read here

Collapse
 
smetzdev profile image
Sascha Metz

Thank you, that looks interesting, gonna give it a try

Collapse
 
ibrahima92 profile image
Ibrahima Ndaw

This is pure joy, you won't regret it

Collapse
 
denvash profile image
Dennis Vash • Edited

Use twin.macro instead, tailwind.macro is outdated.

github.com/ben-rogerson/twin.macro

Collapse
 
ilumin profile image
Lumin • Edited

Cool! instead of put Tailwind class into component, just put it in Styled Component.