Using tailwind v3 with lit elements
James Garbutt
Posted on December 6, 2022
Quite often I see people asking around the Lit community about how to use tailwind inside their Lit elements. This is going to be a brief overview of how you can make that happen.
I've written about this before, but the solutions I used in the past were often inconsistent or flaky. Fortunately, we now have a much more concrete solution available to us!
Setup
For simplicity, I'm going to go with a slightly unrealistic setup:
- lit-element-starter-ts
- directly calling
postcss
CLI on our built JS files
I'll assume you already have some similarly (or hopefully better) setup repo.
This means our source files will live in src/
and our built files will live in ./
. For example, src/my-element.ts
becomes lib/my-element.js
on TypeScript build in this case.
Installing tailwind dependencies
To add tailwind to this setup, we need the following:
The last two are just nice to have, allowing us to lint our source CSS.
All of these are npm packages you can install with npm i
.
How it'll all fit together
We will be using PostCSS to process our source files' CSS.
As part of that, PostCSS will call tailwind to handle the processing of tailwind's classes and what not.
We might also call stylelint so we can lint our source CSS.
In the end, we will have PostCSS write the now transformed sources back out to our build output.
Configuring postcss
Tailwind is essentially just a processor we usually call via either the Tailwind CLI or PostCSS.
In our case, we're going with PostCSS. So let's add a config file postcss.config.cjs
:
module.exports = {
syntax: 'postcss-lit',
plugins: {
tailwindcss: {
config: './tailwind.config.cjs'
}
}
};
At the time of writing this, I had some trouble using ESM for these config files, hence the .cjs
filename. Feel free to try it with .js
or .mjs
depending on your situation.
Two important things happen in the config file above:
- We need to tell PostCSS how to read JS/TS files, specifically those containing Lit elements. We do that by specifying the
syntax
aspostcss-lit
. - We tell PostCSS we want to load tailwind as a plugin, to allow us to make use of tailwind's classes and everything else
Configuring Tailwind
Tailwind normally assumes you store your CSS separate from your JS.
For example, it will scan your JS sources for CSS classes so it can strip them (similar to JS tree shaking) from your CSS files.
This shouldn't work in our case because our CSS and JS lives in the same single file most of the time. In theory, this means every class would be "used" because tailwind would scan its own CSS for usages of its own classes... not what we want.
To solve this, we configure tailwind with a tailwind.config.cjs
like so:
const {tailwindTransform} = require('postcss-lit');
module.exports = {
content: {
files: ['./*.js'],
transform: {
ts: tailwindTransform
}
}
};
We're basically telling it two things here:
- Our source files which make use of tailwind's classes live at
./*.js
. In this dumbed down case, this is true since we're transforming the already built (viatsc
) JS. In your case, however, you may want to point it at your actual source files (the typescript). - A transform which will strip the CSS before tailwind does its class detection, so it doesn't detect its own CSS as usages
Configuring stylelint (optional)
Now that you have PostCSS setup, you can do all sorts of useful stuff. For example, we can setup stylelint to lint our source CSS.
To do that, you can create a .stylelintrc.json
like so:
{
"extends": "stylelint-config-standard",
"customSyntax": "postcss-lit"
}
Again, we're just telling stylelint how to interpret our sources and to apply the standard lint rules.
You can execute this via npx stylelint src/**/*.ts
for example.
If you use a bundler, maybe look for a stylelint plugin if you wish.
Run it
We can now do, for example:
npx postcss -r my-element.js
This would apply tailwind's transforms to our my-element.js
file.
Again, this is a slightly unrealistic setup since we're transforming our TypeScript build output with PostCSS.
In real world repos you probably want this to run against a glob, like postcss -r build/**/*.js
. Or if you use a bundler, use a postcss plugin in your bundler to apply it as part of the bundling process.
Posted on December 6, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024
November 30, 2024