Tailwind 3 shipped with an all new build process, previously referred to as JIT mode.

The gist is that you kick off Tailwind in watch mode and it sits there, keeping an eye on your html, JS and other template files.

Then, as you start to use Tailwind’s classes in your template files (Razor components in our case)…

<div class="p-4">
    A little bit of padding...
</div>

…Tailwind kicks in and rebuilds a static CSS file with the styles you’re using.

This is a handy way to make sure your CSS file only has definitions for the styles you’re actually using, and means you don’t have to run another process to trim all the Tailwind styles you’re not using at a later point.

Running Tailwind 3

If you’re using a JS framework like React, Vue etc. then you easily configure TailwindCSS to run as part of the normal dev process.

For example, with React, you can run npm run start as you would normally (to launch your app in dev mode) and Tailwind will kick in, keeping watch over your app and rebuilding the CSS every time you make changes.

Alternatively, if you’re not using one of those JS frameworks you can use the Tailwind CLI to kick off the watch process instead.

npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch

Here we’re asking Tailwind to take input.css and transform it to dist/output.css.

--watch ensures this process will keep running, and react every time a change is detected.

This second approach will work for your Blazor projects, you just have to run the Tailwind CLI and keep it running when you’re working on your app.

Introducing Tailwind.Extensions.AspNetCore

In the end though, it would be a lot nicer if you could just launch your Blazor app normally, and have Tailwind run in the background, without having to launch it yourself every time.

And so a new NuGet package is born!

Tailwind.Extensions.AspNetCore

This package gives you a way to seamlessly run Tailwind in watch mode as part of your usual process ( using dotnet watch run or your IDE).

It works nicely with Hot Reload too, meaning you can kick off your Blazor project with Hot Reload enabled, make changes and see those changes reflected in your browser (with one caveat, which I’ll get to).

Here’s how to get it working with a .NET 6 Blazor Server app (it also works for Blazor WASM apps that are ASP.NET Core hosted).

Set up Tailwind 3

First you need to install Tailwind, as normal, in the root of your project.

npm install -D tailwindcss cross-env
npx tailwindcss init

We’re installing Tailwind and also a handy little library called cross-env which makes sure we can launch processes on both windows and linux.

The second command creates the default tailwind.config.js file.

tailwind.config.js

module.exports = {
  content: [],
  theme: {
    extend: {},
  },
  plugins: [],
}

Now you’ll want to update that file’s content array, to tell it which files Tailwind should keep an eye on.

module.exports = {
  content: ["**/*.razor", "**/*.cshtml", "**/*.html"],
  theme: {
    extend: {},
  },
  plugins: [],
}

Tailwind needs a stylesheet to start off with (its input file) so you’ll need to create that.

Styles\input.css

@tailwind base;
@tailwind components;
@tailwind utilities;

Finally we need to set up a script in package.json to actually kick off the Tailwind process.

Update package.json to add this script.

  "scripts": {
    "tailwind": "cross-env NODE_ENV=development ./node_modules/tailwindcss/lib/cli.js -i ./Styles/input.css -o ./wwwroot/css/output.css --watch"
  },

This script will launch Tailwind, take the input stylesheet we created earlier, and create a static Tailwind CSS file in wwwroot/css/output.css

Use Tailwind.Extensions.AspNetCore to launch Tailwind’s JIT process

Now the fun bit :)

Add a reference to the Nuget package.

dotnet add package Tailwind.Extensions.AspNetCore --version 1.0.0-beta2

Then head over to Program.cs and add this code, somewhere before app.Run()

using Tailwind; // add this using statement too

...

if (app.Environment.IsDevelopment())
{
    app.RunTailwind("tailwind", "./");
}

The two arguments here are the name of the npm script to run, and the working directory in which to execute the script.

With that, you should now be able to launch your app via dotnet watch run and see the node process kick in every time you make changes to your components and/or input.css file.

Hot Reload Caveat

One thing to note, Hot Reload in Visual Studio is sometimes a little hit and miss.

It seems to work better via dotnet watch at the moment (from my testing at least).

This isn’t specific to Tailwind or this integration, but rather an issue whereby hot reload doesn’t pick up CSS stylesheet changes when working on an ASP.NET Core hosted Blazor application.

This appears to be a known limitation of the current Hot Reload implementation for Visual Studio 2022.

There’s an open Visual Studio feedback item about it: Hot Reload For CSS Not Working With Blazor WebAssembly Hosted.

If you find this is an issue you may prefer to launch your app via dotnet watch instead.

Check out the source code on Github.

There you’ll also find a handy demo Blazor Server app .

The package is available as a pre-release build via NuGet.

Source code, step-by-step tutorials, videos and more

I've compiled a whole load of useful tutorials, source code for articles (like this one) and mini video series to help you push through all the noise and build better ASP.NET web applications, faster.

Drop your email in the box below to get new posts first, and instant access to 'the vault'.

I respect your email privacy. Unsubscribe with one click.

 

Next up

Use the Query String to pass an array of selected values between Blazor Pages
Make your Blazor app support deep linking by passing state in the Query String
Conditional Blazor Styles (without the if statements)
Sometimes you’ll want your Blazor UI to change according to the data you’re using to populate it
Go faster with mockups
Struggling to get “in” to a feature, or know where to start? Try sketching out a mockup.