ReactJS - Tailwind CSS with CSS-IN-JS

ReactJS - Tailwind CSS with CSS-IN-JS

Introduction

In this post, I'll explain what's Tailwind CSS and Twin. As well I'll explain how to integrate them to make use of Tailwind CSS with the power of CSS-IN-JS.

What is Tailwind CSS?

Maybe this is the first time you've heard about Tailwind CSS, so I'll briefly explain what is.

Tailwind CSS is a CSS Framework like Bootstrap but with the difference that Tailwind CSS doesn't have any kind of "components" orientation like Bootstrap.

The great feature of this framework is that it's oriented to "utilities" and thanks to this it gives us full customization of your designs, because of that you don't have to deal with the problem of styles imposed by other frameworks or trying to overwrite classes.

These "utilities" are basically small blocks that allow us to build our site with precision. To make it clearer, below you can see an example of how the HTML code looks with the help of Tailwind CSS:

<div class="mt-10 ml-10">
  <button class="px-6 py-3 bg-blue-500 font-bold text-white rounded shadow">
    I'm a Button!
  </button>
</div>

Output:

Well as you can see, to build a button we must write each small "block" that allows us to style our button, which is very different from Bootstrap in which we already have a class called .btn which provides us the design of a button.

Tailwind CSS with CSS-IN-JS in a ReactJS project

So, let's go back to the main objective of this post, explain how to install and configure Tailwind CSS with CSS-IN-JS on a ReactJS project.

Setting up our ReactJS Project

The first step is to generate or create our React project. In this case, I gonna use the create-react-app package. So, we need to run the following command in our terminal or cmd:

npx create-react-app reactapp-with-tw

Once the project is created, enter in the project folder with:

cd path/to/your/project

Install dependencies

Now that we have our React project ready, let's proceed to install some dependencies that we're going to need and use.

Put the following command in your terminal or cmd:

npm install twin.macro styled-components
# or
yarn add twin.macro styled-components
  • twin.macro: It's a library which basically converts your Tailwind CSS classes intro CSS objects and shares them with styled-components or emotion to give us the power of writing with CSS-IN-JS.
  • styled-components: is a library for React and React Native that allows you to use component-level styles in your application that is written with a mixture of JavaScript and CSS using a technique called CSS-in-JS

Configuration file of Tailwind CSS

As I mentioned in the description of each package, twin reads our configuration file to convert Tailwind CSS classes into CSS objects.

So, let's proceed to create a configuration file for Tailwind CSS. Inside our project folder, run the following command in your terminal or cmd:

npx tailwindcss init
# You can add the --full flag if you want to see the full configuration file of Tailwind CSS

This is the content of the file that was just generated:

// tailwind.config.js
module.exports = {
  future: {
    removeDeprecatedGapUtilities: true,
    purgeLayersByDefault: true,
    defaultLineHeights: true,
    standardFontWeights: true
  },
  purge: [],
  theme: {
    extend: {}
  },
  variants: {},
  plugins: []
};

Is important to clarify that Twin only reads the theme and plugin values.

Set our custom configuration file path

In this step, we need to set the path of our tailwind.config.jsfile, you can do this step in two ways:

  1. Go to your package.json file and put the following code:

    // package.json
    "babelMacros": {
     "twin": {
       "config": "tailwind.config.js",
       "preset": "styled-components",
       "autoCssProp": true,
       "debugProp": true,
       "debugPlugins": false,
       "debug": false,
     }
    },
    
  2. Create a new file called babel-plugin-macros.config.js in our project root:

    // babel-plugin-macros.config.js
    module.exports = {
    twin: {
     config: "tailwind.config.js",
     preset: "styled-components",
     autoCssProp: true,
     debugProp: true,
     debugPlugins: false,
     debug: false
    }
    };
    

Using global styles in our project

Projects using Twin also use the Tailwind preflight base styles to smooth over cross-browser inconsistencies.

Twin has a component to add these styles to our project, go to your entry file or App.js and add the following code:

// src/App.js
import { GlobalStyles } from 'twin.macro';

const App = () => (
  <>
    <GlobalStyles />
    {/* more code */}
  </>
);

export default App;

Using Tailwind CSS with Twin

So now, here is some examples of the things that you can do using Tailwind CSS and Twin.

Prop to JSX Elements

You can pass the tw prop into JSX elements, a good way if you have an element without a lot of classes.

import 'twin.macro';

export default function App() {
  return (
    <h1 tw="text-2xl text-blue-500 font-bold">Hello world</h1>
  );
}

Nesting tw with css prop

In this case, you can pass de css prop to a JSX Element in order to create conditional styles.

In the example, we have a variable called isBold and basically in the css prop check if the isBold is true. If it's true then we will have an element with font-bold class.

import tw from 'twin.macro';

export default function App() {
  const isBold = true;
  return (
    <h1 css={[tw`text-3xl text-blue-500`, isBold && tw`font-bold`]}>Hello world</h1>
  );
}

Mixing SASS styles with the css import

With the css import, we can mix SASS style with our TailwindCSS classes.

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

export default function App() {

  const myCustomStyles = css`
    ${tw`font-bold`}
    &:hover {
      font-weight: 500;
      ${tw`text-black`}
    }
  `;

  return (
    <h1 css={[tw`text-3xl text-blue-500`, myCustomStyles]}>Hello world</h1>
  );
}

Styled Components

With the tw import we can create a Styled Component, good if you have elements that you repeat a lot.

import tw from 'twin.macro';

const MyButton = tw.button`border-2 border-blue-500 px-4 py-2`;

export default function App() {

  return (
      <MyButton>Hello World!</MyButton>
  );
}

And maybe, you want to have a "base" style for a Styled Component, you can Clone and Edit an existing Styled Component.

import tw from 'twin.macro';

const MyButton = tw.button`border-2 border-blue-500 px-4 py-2`;
const MyPrimaryButton = tw(MyButton)`text-white bg-blue-500`; // Cloned Styled Component

export default function App() {

  return (
    <>
      <MyButton>Hello World!</MyButton>
      <MyPrimaryButton>My Second Hello World!</MyPrimaryButton>
    </>
  );
}

Styled Component - Conditional Styles

Maybe you need a conditional style, with styled import we can do it.

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

const MyButton = styled.button(({isBold, isPrimary}) => [
  tw`mt-5 ml-5 border-2 border-blue-500 px-4 py-2`,
  // Ternary
  isBold ? tw`font-bold` : tw`font-semibold`,
  // Conditional Style
  isPrimary && tw`text-white bg-blue-500`
]);


export default function App() {

  return (  
    <MyButton isPrimary>Hello World!</MyButton>
  );
}

In this Styled Component, you can create conditionals styles, passing props to the function in this case we have two "isBold" and "isPrimary". We can use the ternary operator to apply certain classes or styles depending on what we need.

Variant Groups

One of twin.macro's new enhancements are the ability to group classes, which I really loved.

Maybe you're working in the Responsive web design or in multiple classes or styles for the hover pseudo-class.

So, twin.macro allows you to group multiple classes, for example you have the following classes in your Styled Component:

<h1 tw="text-blue-500 bg-blue-500 border-2 border-blue-500 hover:text-blue-900 hover:bg-blue-900 hover:border-blue-500" >Hello World</h1>

Maybe you don't want to re-write hover: prefix to all the classes, now in twin.macro you can do the following:

<h1 tw="text-blue-500 bg-blue-500 hover:(text-blue-900 bg-blue-900)">Hello World</h1>

Do you see it? You only need a single hover:() to add multiple styles that will react to the pseudo-element.

See all variants to Prefix your Classes

Theme

If you have a custom tailwind.config.js file, you can use our custom values of this file with the theme import available in twin.macro.

twin.macro only uses the theme and plugins variables available in tailwind.config.js

Example

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        electric: '#db00ff',
        ribbon: '#0047ff'
      }
    }
  },
  plugins: []
}

So, we have our tailwind.config.js with custom variables, to use it, we need to import the theme in our application.

import tw, { css, theme } from 'twin.macro'  

const App = () => (
  <div
    css={[
      tw`flex flex-col items-center justify-center h-screen`,
      css({
        // Grab values from your config with the theme import
        background: `linear-gradient(
          ${theme`colors.electric`},
          ${theme`colors.ribbon`}
        )`
      })
    ]}
  >
    <h1>Hello World!</h1>
  </div>
)

export default App;

So, as you can see we create a custom linear-gradient using the custom colors that we add to tailwind.config.js. ${theme`color.electric`}

Conclusion

Well, we have it, Twin within our project to take more advantage of using TailwindCSS. If you have anything to add or fix, feel free to let me know in the comments.