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'
};
You can then transform a lit component using the postcss CLI, like so:
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, you can create a stylelint config file like so:
{
"extends": "stylelint-config-standard",
"customSyntax": "postcss-lit"
}
You can then lint your lit components like so:
stylelint src/my-element.js
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'}
};
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: {}
}
};
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
}
}
};
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>
`;
}
}
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)
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?
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 👌