Tailwind v4 with Blazor - It just got easier
Tailwind version 4 was just released. With the new CLI, it is just so much easier to use tailwindcss with Blazor. So in this post, I will show you how to use the new CLI to create a new Blazor project with Tailwind v4.
Short desclaimer: If you still want to use version 3, I already wrote an article about this some time ago: "Blazor with TailwindCSS".
tailwind/cli
The basic installation setup is taken from the official documentation: https://tailwindcss.com/docs/installation/tailwind-cli I will link the sample repository at the end of this post so you can see the full setup.
But here the short gist:
- Create a new Blazor project You can either use your favorite IDE or the dotnet CLI to create a new Blazor project. I will use the dotnet CLI for this example:
dotnet new blazor -o BlazorTailwind
- Install the cli with tailwind:
npm install tailwindcss @tailwindcss/cli
This will create a package.json
(and package-lock.json
) file and a node_modules
folder. Therefore I would recommend adding the node_modules
folder to your .gitignore
file. The package.json looks like this:
{
"dependencies": {
"@tailwindcss/cli": "^4.0.8",
"tailwindcss": "^4.0.8"
}
}
- Use tailwind
Inside your wwwroot/app.css
add tailwind like this on the first line:
@import "tailwindcss";
- Generate the merged css file
We are almost done. The last step is to generate the generated CSS file which consists of all the tailwind classes and your custom definitions in your wwwroot/app.css
file. You can do this by running the following command:
npx @tailwindcss/cli -i wwwroot/app.css -o wwwroot/dist.css
This will generate a dist.css
file in your wwwroot
folder. You can now include this file in your App.razor
instead of the app.css
file like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<base href="/"/>
<link rel="stylesheet" href="dist.css"/>
<link rel="stylesheet" href="@Assets["BlazorTailwind4.styles.css"]"/>
Now let's go to our Home.razor
, use some tailwind classes and run the npx
command again:
<h1 class="p-4 font-bold text-blue-600">Hello, world!</h1>
Will result in:
Now you might have seen, that I did not use the @Assets
directive. And there is a reason. The process I showed is very manual and you have to run the command every time you change something in your app.css
file. But there is a better way to do this.
Automate the process
We can use the npx
command to get executed everytime we build the project. For that let's go to our package.json
:
{
"dependencies": {
"@tailwindcss/cli": "^4.0.8",
"tailwindcss": "^4.0.8"
},
"scripts": {
"build:css": "npx @tailwindcss/cli -i wwwroot/app.css -o wwwroot/base.css"
}
}
With scripts
we can execute commands. So we can now run build:css
everytime we build. To do that, just add the following line to your .csproj
file:
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="npm run build:css" />
</Target>
Now everytime you build your project, the dist.css
file will be generated. That said, you might want to gitignore
the dist.css
file, because it will be generated everytime you build the project anyway. No need to keep the autogenerated file in your repository.
GitHub Actions
The unfortunate thing is, that you have to have node installed on your machine or your GitHub action. So to make a minimal CI pipeline work, you wanto have something like this:
name: Build
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm install
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.x'
- name: Build with dotnet
run: dotnet build --configuration Release
dotnet watch
If you are like me, you are using dotnet watch
aka hot-reload all the time. But there is an inherit problem with tailwindcss and the stuff we built up earlier. dotnet watch
does not invoke the pre-build event. So to come around that fact you basically need two shells open. The first one for your dotnet watch
and the second to let tailwind watch your code:
npx @tailwindcss/cli -i wwwroot/app.css -o wwwroot/dist.css --watch
Now tailwind automatically recognizes changes in your app.css
file and updates the dist.css
file. Of course you can also park that in your package.json
:
{
"dependencies": {
"@tailwindcss/cli": "^4.0.8",
"tailwindcss": "^4.0.8"
},
"scripts": {
"build:css": "npx @tailwindcss/cli -i wwwroot/app.css -o wwwroot/base.css",
"watch:css": "npx @tailwindcss/cli -i wwwroot/app.css -o wwwroot/base.css --watch"
}
}
And just call npm run watch:css