Building Tailwind CSS in an Angular CLI project
Tags: tailwindcss, css, html, angular
Published: 2019-10-04 10:40:45

---
title: Building Tailwind CSS in an Angular CLI project
published: true
description: We are integrating Tailwind CSS, a utility-first CSS framework in an Angular CLI project and stripping away all unused CSS in 'production' mode.
tags: tailwindcss, css, html, angular
cover_image: https://thepracticaldev.s3.amazonaws.com/i/33vvbo2uf9fd8197wnhc.jpg
---

If you are wondering how to use Tailwind CSS in an Angular CLI project and automatically create an optimized CSS bundle during production builds, you've come to the right place!

You can check out a working minimal solution in this [repo](https://github.com/BeaveArony/tailwindcss-angular.git)

## Angular CLI

Ejecting out of the Angular CLI seems like a nightmare to me. Too much of a benefit of generating code, building and configuring quickly. Many tools like [NX](https://nx.dev/angular) build on top of it. Since version 6 of Angular it is not even possible to eject out of the CLI anymore. Instead we've got an extensible builder system to include customization, in case we need it.

The Angular CLI uses webpack under the hood to build and bundle the web app. WebPack might be replaced by another build tool, like Bazel, if it proves to be better. Most cases don't need to customize specific build details, but in our case, it is beneficial to hook into the build system. Fortunately, we have the ability to customize the webpack build by using custom builders.

With the help of [@angular-builders/custom-webpack](https://www.npmjs.com/package/@angular-builders/custom-webpack) we can add some logic to extend the underlying webpack build.

## Tailwind CSS

[Tailwind CSS](https://tailwindcss.com/) is an awesome library to remove the headache of coming up with class names. Everything I need in CSS is defined in HTML and unused styles can be stripped away at build time. I remember those times where I was afraid to remove CSS classes, because these might be used somewhere else. No more! The machine can do it for me.

We will setup an Angular CLI project to compile [Tailwind CSS](https://tailwindcss.com/) with the help of [@angular-builders/custom-webpack](https://www.npmjs.com/package/@angular-builders/custom-webpack) to include a build step into the default webpack config. [PostCSS](https://github.com/postcss/postcss#usage) will load our Tailwind root file and process it with additional vendor prefixes and remove unused classes with the [PurgeCSS](https://github.com/FullHuman/postcss-purgecss) plugin. You can find more information about this process in the official [Tailwind Documentation about **Controlling File Size**](https://tailwindcss.com/docs/controlling-file-size).

To not slow us down during development, we will configure it to only run the PurgeCSS process during production builds.

## Separating Tailwind CSS from the rest

I find it better to separate Tailwind into its own file `./src/tailwind.scss` instead of putting the Tailwind's base, components, and utilities styles directly into our CSS. This way I can target the custom build to only this file and leave the rest as it is. Other component libraries like [Angular Material](https://material.angular.io) can be added without worrying about the intermingled build process.

We can also use whatever style system we like (ie. CSS, SCSS, LESS ...) in our app. Tailwind will just work, can be used in any template and will only put the styles we actually use into our final bundle. I don't see a reason to write any CSS in any components with this setup.

> If you want to change the default **_ng generate component_** component to **NOT** create the styles file, you can use this command to default to inline styles in your app:

```sh
ng config projects.<my-project>.schematics.@schematics/angular:component.inlineStyle true
```

## Set it up

### Create the Angular Project

Install the Angular CLI, if you haven't done so:

```sh
npm i -g @angular/cli
```

Create a new Angular CLI project:

```sh
ng new tailwindcss-angular
cd tailwindcss-angular
```

### Install dependencies

Install the packages into the project:

```sh
npm i tailwindcss
npm i -D @angular-builders/custom-webpack @fullhuman/postcss-purgecss
```

### Initialize Tailwind CSS

Create a tailwind.config.js file by running this command:

```sh
npx tailwind init
```

This can be used to customize Tailwind with themes, colors, breakpoints, spacing and many others.

Create a new file `src/tailwind.scss` with this content:

```scss
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Customize the build process

Create another new file `extra-webpack.config.js` in the root folder of our project and add this content:

```js
const purgecss = require('@fullhuman/postcss-purgecss')({
  // Specify the paths to all of the template files in your project
  content: ['./src/**/*.html', './src/**/*.component.ts'],
  // Include any special characters you're using in this regular expression
  defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
});

module.exports = (config, options) => {
  console.log(`Using '${config.mode}' mode`);
  config.module.rules.push({
    test: /tailwind\.scss$/,
    use: [
      {
        loader: 'postcss-loader',
        options: {
          plugins: [
            require('tailwindcss')('./tailwind.config.js'),
            require('autoprefixer'),
            ...(config.mode === 'production' ? [purgecss] : [])
          ]
        }
      }
    ]
  });
  return config;
};
```

> [Autoprefixer](https://github.com/postcss/autoprefixer) automatically adds vendor prefixes. Leave it out, if you don't need this.

## Configure angular.json

Then, to use these files open up `angular.json` and look for the **_"architect"_** section. You need to customize the **ng build** and **ng serve** parts.

You can do it by editing the `angular.json` file directly or use the **ng config** command.

So you do this twice, once for **build** and once for **serve**:

1. Replace **_@angular-devkit/build-angular_** with **_@angular-builders/custom-webpack_**
2. Add the **_customWebpackConfig_** path to the **_options_**

### Make changes to the **build** section

```sh
ng config projects.<my-project>.architect.build.builder @angular-builders/custom-webpack:browser
```

```sh
ng config projects.<my-project>.architect.build.options.customWebpackConfig.path extra-webpack.config.js
```

### Make changes to the **serve** section

```sh
ng config projects.<my-project>.architect.serve.builder @angular-builders/custom-webpack:dev-server
```

```sh
ng config projects.<my-project>.architect.serve.options.customWebpackConfig.path extra-webpack.config.js
```

### Add the tailwind.scss file to the styles array

Don't forget to add the `tailwind.scss` path to the styles array. This is probably best done directly in the `angular.json` file. In case you want to do it with a command, this will add the file to the second index of the array or replace anything that is configured in that slot. So be careful not to overwrite anything.

```sh
ng config projects.<my-project>.architect.build.options.styles[1] src/tailwind.scss
```

### Summarized changes to **angular.json**

In total there are 9 lines affected. The final outcome of all our changes should look like this:

```js
"architect": {
  "build": {
    "builder": "@angular-builders/custom-webpack:browser", // ←
    "options": {
      "customWebpackConfig": {            // ←
        "path": "extra-webpack.config.js" // ←
      },                                  // ←
      // ...
      "styles": [
        "src/tailwind.scss",              // ←
        "src/styles.css"
      ],
    // ...
    }
  },
  "serve": {
    "builder": "@angular-builders/custom-webpack:dev-server", // ←
    "options": {
      "customWebpackConfig": {            // ←
        "path": "extra-webpack.config.js" // ←
      },                                  // ←
    // ...
    }
  }
}
```

## Test it out

Everything should be in place now. To see if if it worked correctly, replace the content of `./src/app.component.html` with some HTML that uses Tailwind CSS classes or use this:

```html
<div class="max-w-lg mx-auto bg-white shadow-lg rounded-lg overflow-hidden">
  <div class="sm:flex sm:items-center px-6 py-4">
    <div
      class="flex items-center justify-center sm:flex-col sm:w-24 sm:border sm:border-gray-500 sm:rounded-full"
    >
      <img
        class="block sm:mx-auto mx-0 flex-shrink-0 h-16 sm:h-12"
        src="https://angular.io/assets/images/logos/angular/angular.svg"
        alt="Angular Logo"
      />
      <img
        class="block sm:mx-auto mx-0 flex-shrink-0 h-16 sm:h-12"
        src="https://tailwindcss.com/android-chrome-512x512.png"
        alt="Tailwind CSS Logo"
      />
    </div>

    <div class="mt-4 sm:mt-0 sm:ml-4 text-center sm:text-left">
      <p class="text-xl leading-tight">Tailwind CSS & Angular CLI</p>
      <p class="text-sm leading-tight text-gray-600">
        With custom webpack configuration!
      </p>
      <div class="mt-4">
        <button
          class="text-purple-500 hover:text-white hover:bg-purple-500 border border-purple-500 text-xs font-semibold rounded-full px-4 py-1 leading-normal"
        >
          GO
        </button>
      </div>
    </div>
  </div>
</div>
```

To see the result in a web browser run `ng serve`. To see the build output run `ng build --prod` and take a look into the `dist/tailwindcss-angular/styles.########.css` file.

Tailwind CSS automatically adds [normalize.css](https://github.com/necolas/normalize.css). You will see these styles in the beginning of the file.
It will also **only** contain the css classes used by your app. Everything else is stripped out.

## Summary

We learned how to make changes to the build process of our Angular CLI project to compile Tailwind CSS with just a few simple steps.

1. Install the custom-webpack, purgecss and tailwindcss dependencies
2. Init tailwindcss and create a `tailwind.scss` file
3. Create a `extra-webpack.config.js` file with the build config
4. Adjust `angular.json`

Happy styling your Angular components without writing CSS!