DEV Community 👩‍💻👨‍💻

James Garbutt
James Garbutt

Posted on

Using tailwind, postcss and stylelint with lit-element projects

I've written various posts 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, 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 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 simply by configuring postcss correctly!

postcss-lit

To make use of this new capability, I have released postcss-lit.

This is a custom syntax implementation you can use with postcss to parse CSS inside your lit 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, creating a config file like so:

module.exports = {
  syntax: 'postcss-lit'
};
Enter fullscreen mode Exit fullscreen mode

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

postcss -r src/my-element.js
Enter fullscreen mode Exit fullscreen mode

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, you can create a stylelint config file like so:

{
  "extends": "stylelint-config-standard",
  "customSyntax": "postcss-lit"
}
Enter fullscreen mode Exit fullscreen mode

You can then lint your lit components like so:

stylelint src/my-element.js
Enter fullscreen mode Exit fullscreen mode

Using postcss & webpack with lit

If you use webpack, you can quite easily follow these instructions and create a config like so:

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

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, creating a postcss config like so:

module.exports = {
  syntax: 'postcss-lit',
  plugins: {
    tailwindcss: {}
  }
};
Enter fullscreen mode Exit fullscreen mode

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:

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

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

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:

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

    :host {
      display: block;
    }
  `;

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

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 team and IBM (mostly abdonrd) for testing this.

Top comments (2)

Collapse
 
lukasergio profile image
luka-TU

Is there a way to set it up to process both css-in-js and also css extraction into a separate file for non-lit stuff?

Collapse
 
zer0cool profile image
Cookie Thief

This doesn't seem to work in any of my projects, can we have a working boilerplate on github ? thanks a lot for your work 👌

🌚 Friends don't let friends browse without dark mode.

Good news! You can update to dark mode in your DEV settings.