Using Tailwind CSS Framework with Angular

December 7, 2019 in Tooling

Symbolic image showing Angular and TailwindCSS Logo working together

Tailwind CSS brings a fundamentally new approach to the world of css frameworks, making it one of most promising newcomers in the ring so far.

What is Tailwind CSS?

Tailwind CSS is a highly customizable, low-level CSS framework that gives us all of the building blocks we need to build bespoke designs without any annoying opinionated styles we have to fight to override.

Which means, Tailwind CSS is not going to give us anything close to what Bootstrap and UiKit would give us in terms of pre-built components. The only thing it gives us is lots of utility classes. That doesn't sound too awesome, does it?

Well, the nice part about it is that these utility classes are well thought through, and highly customizable through a simple JSON configuration file. With this configuration we are essentially defining the boundaries of what is possible from a design perspective for our website or webapp.

Using only these customized utilities in return guarantees us to be in line with the design system that has been defined upfront.

Check out their website for more detailed intro and explanation of how it works: Tailwind CSS Framework

How to integrate it in Angular?

So let's get going integrating it into our build process. Having our Angular project already set up we are eager to modify some configuration files!

As a first step, we will be using the newly introduced @angular-builders/custom-webpack package to extend our build done by the Angular CLI, without the need to eject the webpack configuration or other nonsense.

npm i tailwindcss postcss-loader postcss-scss postcss-import autoprefixer @angular-builders/custom-webpack -D

What are we installing here?

  • tailwindcss - No brainer, of course we need tailwind css itself
  • postcss-loader - PostCSS Loader for webpack
  • postcss-scss - SCSS parser for postcss
  • postcss-import - PostCSS plugin to inline @import rules content
  • autoprefixer - PostCSS plugin to add vendor prefixes to CSS rules.
  • @angular-builders/custom-webpack - Custom webpack builder facade for Angular

Having done that, we are going to open up our src/styles.scss file and add the following 3 tailwind directives at the top of the file.

@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

@import vs @tailwind

You might be wondering why we are using @import instead of the more famous @tailwind directive. Easy answer on that one.

Tailwind CSS directives have to be the first thing to be included, otherwise we wouldn't be able to customize them.

But as we are using postcss-import which specifies that all @import statements have to come first before normal scss code, we are running into a dilemma here.

Looking closer into the imported tailwind files like base.css, we can see that it's content is nothing more than

@tailwind base;

So exactly what we would have written without that postcss-import limitation.

Having that settled, we ought to proceed by generating the default tailwind configuration file.

npx tailwind init

This will generate the tailwind.config.js file in our project root directory. We are not going to change it for now, using the default tailwind configuration as is.

Next up is the setup of the webpack configuration, therefore we need create webpack.config.js in our project root directory, adding the following content:

module.exports = {
    module: {
        rules: [
            {
                test: /\.scss$/,
                loader: 'postcss-loader',
                options: {
                    ident: 'postcss',
                    syntax: 'postcss-scss',
                    plugins: () => [
                        require('postcss-import'),
                        require('tailwindcss'),
                        require('autoprefixer'),
                    ]
                }
            }
        ]
    }
};

This will essentially tell webpack to use the installed postcss-loader for all *.scss files, via the postcss-scss extension the files are read and processed by the plugins postcss-import, tailwindcss and autoprefixer. In that order.

The output will basically be the same as the default Angular CLI build would give us, but with Tailwind CSS this time of course.

As a last step, we ought to edit the angular.json configuration file.

We are switching the builder property to @angular-builders/custom-webpack:browser, and extend the options section to use our custom webpack configuration:

{
  "architect": {
    "build": {
      "builder": "@angular-builders/custom-webpack:browser",
      // ...
      "options": {
        "customWebpackConfig": {
          "path": "./webpack.config.js"
        }
        // ...
      }
      // ...
    },
    "serve": {
      "builder": "@angular-builders/custom-webpack:dev-server",
      // ...
      "options": {
        "customWebpackConfig": {
          "path": "./webpack.config.js"
        }
      }
      // ...
    }
    // ...
  }
}

Well, now we are basically done! We have successfully included Tailwind CSS into our Angular build process using the custom webpack builder, but wait, there is more...

Adding PurgeCSS to control stylesheet size

After running ng build --prod for the first time, and inspecting the generated output, you might have been a little disappointed that by adding tailwind you also added about 0,5 MB of CSS code, just like that. How come?

As described above, Tailwind CSS is a utility based CSS framework, shipping with hundreds of helper classes, in all different variants. This adds up, so it is advisable to use PurgeCSS to get rid of all those utility classes we aren't using at the moment.

Continuing on that, we'll have to install the following additional development dependency:

npm i @fullhuman/postcss-purgecss -D

This installs purgecss as a postcss plugin.

After that, it is time to edit our webpack.config.js file one more time to mirror the following:

const purgecss = require('@fullhuman/postcss-purgecss')({

  // Specify the paths to all of the template files in your project
  content: [
    './src/**/*.html',
  ],

  // Include any special characters you're using in this regular expression
  defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
});

module.exports = {
  module: {
    rules: [
      {
        test: /\.scss$/,
        loader: 'postcss-loader',
        options: {
          ident: 'postcss',
          syntax: 'postcss-scss',
          plugins: () => [
            require('postcss-import'),
            require('tailwindcss'),
            purgecss,
            require('autoprefixer'),
          ]
        }
      }
    ]
  }
};

And... that's it. What has changed? We configured purgecss to check the generated CSS against our HTML files in src/, we defined a defaultExtractor matching our css class names, and we added the configured purgecss instance in the postcss plugin chain.

This way only classes we are actively using are going to be present in the generated stylesheet.

Congratulations!

By following the steps described in the article above, you should now have set up Tailwind CSS for your Angular project without loosing any of the already present functionality given by the Angular CLI!

By using PurgeCSS you even went as far as to slim the Tailwind CSS framework down to the smallest version possible, specifically tailored to your project.