Skip to content

Instantly share code, notes, and snippets.

@arkada38
Last active February 4, 2024 14:39
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save arkada38/74d2787b2fa092a723ba6892cc3b2ed1 to your computer and use it in GitHub Desktop.
Save arkada38/74d2787b2fa092a723ba6892cc3b2ed1 to your computer and use it in GitHub Desktop.
Using Tailwind CSS v3.2 with Blazor (.Net 6 or above)

Using Tailwind CSS v3.2 with Blazor (.Net 6 or above)

This method works for Blazor Server and Blazor WebAssembly with hot reload, style isolation and tailwind jit compilation.

Setup with using Standalone Tailwind CSS CLI without Node.js

For this method you need added to path Tailwind CSS CLI binary. Read more about Standalone CLI.

Just create a StaticAssets folder in the root of your project with next structure.

StaticAssets
├──styles.css
├──tailwind.config.js
└──TailwindCli.targets

Import TailwindCli.targets into your .csproj file.

<Project Sdk="Microsoft.NET.Sdk.Web">

  ...

  <Import Project="StaticAssets\TailwindCli.targets" />

</Project>

Change your Pages/_Layout.cshtml file if you are using Blazor Server
or wwwroot/index.html file if you are using Blazor WebAssembly.
Add css link

<link href="css/styles.css" rel="stylesheet" />

Run this command in the terminal (change {ProjectDirectory} to project directory). Actualy you can see the text of this command after calling dotnet build, dotnet run or dotnet watch.

cd {ProjectDirectory}/StaticAssets/ && tailwindcss -i styles.css -o {ProjectDirectory}/wwwroot/css/styles.css -w

If you are using github workflows with your project then you need to add additional step.

...
    - name: Setup Tailwind CSS
      run: |
        curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64
        chmod +x tailwindcss-linux-x64
        sudo mv tailwindcss-linux-x64 /usr/bin/tailwindcss
...

Setup with using Node.js and npm

Just create a StaticAssets folder in the root of your project with next structure.

StaticAssets
├──package.json
├──styles.css
├──tailwind.config.js
└──TailwindNpm.targets

Import TailwindNpm.targets into your .csproj file.

<Project Sdk="Microsoft.NET.Sdk.Web">

  ...

  <Import Project="StaticAssets\TailwindNpm.targets" />

</Project>

Change your Pages/_Layout.cshtml file if you are using Blazor Server
or wwwroot/index.html file if you are using Blazor WebAssembly.
Add css link

<link href="css/styles.css" rel="stylesheet" />

Run this command in the terminal (change {ProjectDirectory} to project directory). Actualy you can see the text of this command after calling dotnet build, dotnet run or dotnet watch.

cd {ProjectDirectory}/StaticAssets/ && npx --no-install tailwindcss -i styles.css -o {ProjectDirectory}/wwwroot/css/styles.css -w
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<!-- If you are using Node.js with npm -->
<Import Project="StaticAssets\TailwindNpm.targets" />
<!-- If you are using Standalone Tailwind CSS CLI -->
<Import Project="StaticAssets\TailwindCli.targets" />
</Project>
@using Microsoft.AspNetCore.Components.Web
@namespace Blazor.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link href="css/styles.css" rel="stylesheet" />
<link href="@(nameof(Blazor)).styles.css" rel="stylesheet" />
</head>
<body>
@RenderBody()
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
@tailwind base;
@tailwind components;
@tailwind utilities;
{
"devDependencies": {
"autoprefixer": "^10.4.7",
"tailwindcss": "^3.1.1"
}
}
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'../{Pages,Shared}/**/*.{cshtml,razor,cs,css}'
],
theme: {
extend: {},
},
plugins: [
]
}
<Project>
<ItemGroup>
<AvailableItemName Include="TailwindCli" />
</ItemGroup>
<ItemGroup>
<Content Update="StaticAssets/*" CopyToPublishDirectory="Never" />
</ItemGroup>
<Target Name="CheckIfTailwindCssIsInstalled">
<PropertyGroup>
<TailwindCssTestCommand Condition="$(OS) == Windows_NT">tailwindcss -h &gt; NUL</TailwindCssTestCommand>
<TailwindCssTestCommand Condition="$(OS) != Windows_NT">tailwindcss -h &gt; /dev/null</TailwindCssTestCommand>
</PropertyGroup>
<Exec Command="$(TailwindCssTestCommand)" IgnoreExitCode="true" EchoOff="true">
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="Tailwind CSS is required to build and run this project. To continue, please install Tailwind CSS from https://github.com/tailwindlabs/tailwindcss/releases/latest, and then restart your command prompt or IDE." Condition="$(ExitCode) != 0" />
</Target>
<Target Name="ProcessScopedCssFiles" AfterTargets="_GenerateScopedCssFiles">
<MSBuild Projects="$(MSBuildProjectFile)" Properties="CurrentScopedCssFile=%(_ScopedCssOutputs.Identity)" Targets="PostScopedCssCompile"></MSBuild>
</Target>
<Target Name="PostScopedCssCompile" AfterTargets="ProcessScopedCssFiles" DependsOnTargets="CheckIfTailwindCssIsInstalled" Condition="$(CurrentScopedCssFile) != ''">
<Message Importance="high" Text="Building scoped css..." />
<Exec Command="tailwindcss -i $(CurrentScopedCssFile) -o $(CurrentScopedCssFile) -c ./tailwind.config.js" IgnoreExitCode="true" EchoOff="true" WorkingDirectory="$(MSBuildThisFileDirectory)">
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="Error via build scoped css" Condition="$(ExitCode) != 0" />
</Target>
<Target Name="BuildCss" BeforeTargets="CoreBuild" DependsOnTargets="PostScopedCssCompile" Outputs="$(MSBuildProjectDirectory)/wwwroot/css/styles.css">
<Message Text="Starting tailwindcss. This may take a while..." />
<Exec Command="tailwindcss -i styles.css -o $(MSBuildProjectDirectory)/wwwroot/css/styles.css -m" IgnoreExitCode="true" EchoOff="true" WorkingDirectory="$(MSBuildThisFileDirectory)" EnvironmentVariables="NODE_ENV=production">
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="Error via build css" Condition="$(ExitCode) != 0" />
</Target>
<Target Name="PostStylesCssCompile" AfterTargets="Build">
<Message Importance="high" Text="Run this command if you are in the watch mode" />
<Message Importance="high" Text="cd $(MSBuildThisFileDirectory) &amp;&amp; tailwindcss -i styles.css -o $(MSBuildProjectDirectory)/wwwroot/css/styles.css -w" />
</Target>
</Project>
<Project>
<ItemGroup>
<AvailableItemName Include="TailwindNpm" />
</ItemGroup>
<ItemGroup>
<Content Update="StaticAssets/*" CopyToPublishDirectory="Never" />
</ItemGroup>
<Target Name="CheckIfNodeJSIsInstalled">
<PropertyGroup>
<NodeTestCommand Condition="$(OS) == Windows_NT">node -v &gt; NUL</NodeTestCommand>
<NodeTestCommand Condition="$(OS) != Windows_NT">node -v &gt; /dev/null</NodeTestCommand>
</PropertyGroup>
<Exec Command="$(NodeTestCommand)" IgnoreExitCode="true" EchoOff="true">
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." Condition="$(ExitCode) != 0" />
</Target>
<Target Name="NpmInstall" DependsOnTargets="CheckIfNodeJSIsInstalled" Condition="!Exists('$(MSBuildThisFileDirectory)package-lock.json')">
<!-- If package-lock.json does not exists, perform an NPM install -->
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec Command="npm i" WorkingDirectory="$(MSBuildThisFileDirectory)" />
<Copy SourceFiles="$(MSBuildThisFileDirectory)package-lock.json" DestinationFolder="$(BaseIntermediateOutputPath)" SkipUnchangedFiles="true" />
</Target>
<Target Name="NodeModulesInstall" DependsOnTargets="NpmInstall" Condition="!Exists('$(MSBuildThisFileDirectory)node_modules')">
<!-- If node_modules does not exists, perform an NPM clean install -->
<Message Importance="high" Text="Restoring node_modules using 'npm'. This may take several minutes..." />
<Exec Command="npm ci --also=dev" WorkingDirectory="$(MSBuildThisFileDirectory)" />
<Copy SourceFiles="$(MSBuildThisFileDirectory)package-lock.json" DestinationFolder="$(BaseIntermediateOutputPath)" SkipUnchangedFiles="true" />
</Target>
<Target Name="NpmCleanInstall" DependsOnTargets="NodeModulesInstall" Inputs="$(MSBuildThisFileDirectory)package-lock.json" Outputs="$(BaseIntermediateOutputPath)package-lock.json">
<!-- If package-lock.json has changed, perform an NPM clean install -->
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec Command="npm ci --also=dev" WorkingDirectory="$(MSBuildThisFileDirectory)" />
<Copy SourceFiles="$(MSBuildThisFileDirectory)package-lock.json" DestinationFolder="$(BaseIntermediateOutputPath)" SkipUnchangedFiles="true" />
</Target>
<Target Name="ProcessScopedCssFiles" AfterTargets="_GenerateScopedCssFiles">
<MSBuild Projects="$(MSBuildProjectFile)"
Properties="CurrentScopedCssFile=%(_ScopedCssOutputs.Identity)"
Targets="PostScopedCssCompile">
</MSBuild>
</Target>
<Target Name="PostScopedCssCompile" AfterTargets="ProcessScopedCssFiles" DependsOnTargets="NpmCleanInstall" Condition="$(CurrentScopedCssFile) != ''">
<Message Importance="high" Text="Building scoped css..." />
<Exec Command="npx --no-install tailwindcss -i $(CurrentScopedCssFile) -o $(CurrentScopedCssFile) -c ./tailwind.config.js"
IgnoreExitCode="true"
EchoOff="true"
WorkingDirectory="$(MSBuildThisFileDirectory)">
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="Error via build scoped css" Condition="$(ExitCode) != 0" />
</Target>
<Target Name="BuildCss" BeforeTargets="CoreBuild" DependsOnTargets="PostScopedCssCompile" Outputs="$(MSBuildProjectDirectory)/wwwroot/css/styles.css">
<Message Text="Starting tailwindcss. This may take a while..." />
<Message Importance="high" Text="npx --no-install tailwindcss -i styles.css -o $(MSBuildProjectDirectory)/wwwroot/css/styles.css -m" />
<Exec Command="npx --no-install tailwindcss -i styles.css -o $(MSBuildProjectDirectory)/wwwroot/css/styles.css -m"
IgnoreExitCode="true"
EchoOff="true"
WorkingDirectory="$(MSBuildThisFileDirectory)"
EnvironmentVariables="NODE_ENV=production">
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="Error via build css" Condition="$(ExitCode) != 0" />
</Target>
<Target Name="PostStylesCssCompile" AfterTargets="Build">
<Message Importance="high" Text="Run this command if you are in the watch mode" />
<Message Importance="high" Text="cd $(MSBuildThisFileDirectory) &amp;&amp; npx --no-install tailwindcss -i styles.css -o $(MSBuildProjectDirectory)/wwwroot/css/styles.css -w" />
</Target>
</Project>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>BlazorApp</title>
<base href="/" />
<link href="css/styles.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="Blazor.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">Loading...</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
@caseyspaulding
Copy link

Thank u

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment