Using tailwind, postcss and stylelint with lit-element projects
Published: 2021-12-20 16:30:18

I've written [various](https://dev.to/43081j/using-tailwind-at-build-time-with-web-components-1bhm) [posts](https://dev.to/43081j/using-tailwind-at-run-time-with-web-components-47c) about using tailwind with lit components. Those solutions still work, but this post will outline a simpler method you can use for stylelint and postcss in general, too.

## What's new?

As of [postcss 8.3](https://github.com/postcss/postcss/blob/main/CHANGELOG.md#83-duke-murmur), postcss now has a native way of handling documents containing multiple stylesheets.

In the past, plugins worked around this limitation by fabricating one huge stylesheet made up of all the CSS found in your JS files.

On top of this, [stylelint 14](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md#1400) introduces support for directly using a custom postcss syntax rather than needing a separate stylelint-bound plugin.

## What does this mean?

This means the monolithic plugins of the past (which tried to handle _all_ css-in-js types) will soon be deprecated if they haven't already, and instead you will simply specify the right "syntax" for reading the files in your project.

**What's great is this also means we can now directly use frameworks like [tailwind](https://github.com/tailwindlabs/tailwindcss) simply by configuring postcss correctly!**

## postcss-lit

To make use of this new capability, I have released [postcss-lit](https://github.com/43081j/postcss-lit).

This is a custom syntax implementation you can use with postcss to parse CSS inside your [lit](https://lit.dev/) components.

## Using PostCSS with lit

The most basic setup would be to use:

- PostCSS CLI
- postcss-lit

You can do this by following [these instructions](https://github.com/43081j/postcss-lit#usage-with-postcss), creating a config file like so:

```ts
module.exports = {
  syntax: 'postcss-lit'
};
```

You can then transform a lit component using the postcss CLI, like so:

```sh
postcss -r src/my-element.js
```

This will process the CSS in your element and write back to the same file. **In real world, you probably want to run this on build rather than changing your source file.**

## Using stylelint with lit

Very similar to using postcss with lit, you can use stylelint too. Using [these instructions](https://github.com/43081j/postcss-lit#usage-with-stylelint), you can create a stylelint config file like so:

```ts
{
  "extends": "stylelint-config-standard",
  "customSyntax": "postcss-lit"
}
```

You can then lint your lit components like so:

```sh
stylelint src/my-element.js
```

## Using postcss & webpack with lit

If you use webpack, you can quite easily follow [these instructions](https://github.com/43081j/postcss-lit#postcss-with-webpack) and create a config like so:

```ts
module.exports = {
  entry: './src/main.js',
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['postcss-loader'],
        exclude: /node_modules/
      }
    ]
  },
  output: {filename: 'bundle.js'}
};
```

This will process your CSS templates via postcss before producing your JS bundle. Simple as that.

Your bundle will now contain whatever CSS you configured postcss to transform.

## Using tailwind

Just as easy, set everything up the same way as if you were going to use postcss by itself. Then follow [these instructions](https://github.com/43081j/postcss-lit#usage-with-tailwind), creating a postcss config like so:

```ts
module.exports = {
  syntax: 'postcss-lit',
  plugins: {
    tailwindcss: {}
  }
};
```

Now, tailwind has a concept of "content", files you want it to scan to detect which classes we have used. In our case, we want it to scan our JS (or typescript), though tailwind will have no idea how to parse these files.

To solve this problem, we need to configure tailwind like so:

```ts
const {tailwindTransform} = require('postcss-lit');

module.exports = {
  content: {
    files: ['./src/**/*.js'],
    transform: {
      js: tailwindTransform
    }
  }
};
```

Here we are simply telling tailwind to pass content files through our transform before it tries to detect class usages.

Under the hood, we need to do this so we can strip CSS templates from the content before scanning it, otherwise we'd incorrectly detect CSS names as usages.

You can then use tailwind inside your lit component:

```ts
class MyElement extends LitElement {
  static override styles = css`
    @tailwind base;
    @tailwind utilities;

    :host {
      display: block;
    }
  `;

  render() {
    return html`
      <h1 class="text-3xl">Hello!</h1>
    `;
  }
}
```

## Wrap-up

In the past, these kinds of setup have been a real pain either solved by monolithic packages or by convoluted solutions. The introduction of `customSyntax` to stylelint is great, as a postcss syntax can be used as-is. Just the same, postcss' introduction of a `Document` allows us to parse multiple stylesheets from our JS files.

Some may ask why I have made postcss-lit specific to lit, too. This is mostly on advice from the stylelint and postcss authors, as they want to move away from having huge "solve all" packages.

The package is also very new, so feedback would be appreciated so much.

Big thanks to the [vaadin](https://github.com/vaadin) team and IBM (mostly [abdonrd](https://github.com/abdonrd)) for testing this.