This guide targets Tailwind CSS 4.3.2, the version ShellUI uses.
| Method | Setup | Build integration | Node.js | Use for |
|---|---|---|---|---|
| Play CDN | One browser package | No local build | No | Prototypes and demos only |
| Standalone | One platform-specific CLI binary | MSBuild target | No | A .NET/Blazor project without Node.js |
| npm | tailwindcss plus @tailwindcss/cli |
npm or MSBuild | Yes | Projects that already use Node.js or plugins |
The standalone CLI is downloaded once per machine into ~/.shellui/bin (%USERPROFILE%\.shellui\bin on Windows) as tailwindcss-4.3.2-<platform>, and every project builds with that one copy, so projects hold no binary. Set SHELLUI_CACHE_DIR to keep it somewhere else. A project that needs its own copy can put it at .shellui/bin/tailwindcss.exe (Windows) or .shellui/bin/tailwindcss (macOS, Linux), and the build uses that instead. .shellui/ contains a .gitignore of *, so nothing in it is committed.
The download streams to a .partial file, resumes after a dropped connection, retries, and only gives up when no data arrives for a minute, so a slow connection is fine. If it still fails, init finishes the rest of the setup and warns, and the next dotnet build tries again. Its warning names the exact URL and the file to save it as if you want to download it yourself.
For a production Blazor application, use either the standalone or npm workflow and build the CSS as part of the project. The Play CDN is a prototyping convenience and does not provide the same production build and caching behavior.
- .NET 10.0 SDK
- A Blazor project
- Node.js and npm only when using the npm method
dotnet tool install -g ShellUI.CLI
Run this from the project directory:
shellui init
The default standalone method downloads the Tailwind 4.3.2 standalone executable into .shellui/bin, creates the CSS entry point and output file, wires an MSBuild target, and creates the ShellUI component folders. To choose npm explicitly:
shellui init --tailwind npm --yes
Other initialization options include --style, --force, and --yes. The current CLI's npm setup invokes npm through cmd; use standalone mode on non-Windows systems or run the npm commands manually.
The current CLI command surface is:
shellui init
shellui add <components>
shellui list
shellui remove <components>
shellui update [components]
shellui theme init <url>
shellui theme apply <url>
shellui theme update
Examples:
shellui add button input card
shellui list
shellui remove card
shellui update
list shows the direct targets in the registry. Dependencies are resolved recursively from ComponentRegistry; hidden support entries are not separate public choices in the list.
Create wwwroot/input.css:
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));Tailwind v4 uses the CSS entry point above. The older v3 layer-import sequence is not part of this setup.
Create wwwroot/app.css as the generated output placeholder. Edit input.css, not the generated output.
Create the project-local cache directory first.
Windows PowerShell:
New-Item -ItemType Directory -Force ".shellui/bin" | Out-Null
curl.exe -fL -o ".shellui/bin/tailwindcss.exe" "https://github.com/tailwindlabs/tailwindcss/releases/download/v4.3.2/tailwindcss-windows-x64.exe"Linux:
mkdir -p .shellui/bin
curl -fL -o .shellui/bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/download/v4.3.2/tailwindcss-linux-x64
chmod +x .shellui/bin/tailwindcss
macOS:
mkdir -p .shellui/bin
curl -fL -o .shellui/bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/download/v4.3.2/tailwindcss-macos-x64
chmod +x .shellui/bin/tailwindcss
The correct project-local cache paths are:
- Windows:
.shellui/bin/tailwindcss.exe - Linux:
.shellui/bin/tailwindcss - macOS:
.shellui/bin/tailwindcss
Create Build/ShellUI.targets:
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<ShellUIBinPath Condition="'$(ShellUIBinPath)' == ''">$(MSBuildProjectDirectory)\.shellui\bin</ShellUIBinPath>
<TailwindExecutable Condition="'$(OS)' == 'Windows_NT'">$(ShellUIBinPath)\tailwindcss.exe</TailwindExecutable>
<TailwindExecutable Condition="'$(OS)' != 'Windows_NT'">$(ShellUIBinPath)/tailwindcss</TailwindExecutable>
<TailwindInputCss Condition="'$(TailwindInputCss)' == ''">$(MSBuildProjectDirectory)\wwwroot\input.css</TailwindInputCss>
<TailwindOutputCss Condition="'$(TailwindOutputCss)' == ''">$(MSBuildProjectDirectory)\wwwroot\app.css</TailwindOutputCss>
<TailwindMinify Condition="'$(Configuration)' == 'Release'">--minify</TailwindMinify>
<TailwindMinify Condition="'$(Configuration)' != 'Release'"></TailwindMinify>
</PropertyGroup>
<Target Name="BuildTailwindCSS" BeforeTargets="BeforeBuild" Condition="Exists('$(TailwindExecutable)') AND Exists('$(TailwindInputCss)')">
<Message Importance="high" Text="Building Tailwind CSS..." />
<Exec Command=""$(TailwindExecutable)" -i "$(TailwindInputCss)" -o "$(TailwindOutputCss)" $(TailwindMinify)" />
<Message Importance="high" Text="Tailwind CSS built successfully!" />
</Target>
<Target Name="CleanTailwindCSS" AfterTargets="Clean" Condition="Exists('$(TailwindOutputCss)')">
<Message Importance="high" Text="Cleaning Tailwind CSS output..." />
<Delete Files="$(TailwindOutputCss)" />
</Target>
</Project>Import it from the project file:
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="Build\ShellUI.targets" />
</Project>The target points at .shellui/bin, matching the download location above. Keep the executable in that project-local directory so the target and the downloaded binary agree.
Build manually with the project-local executable:
.shellui/bin/tailwindcss -i wwwroot/input.css -o wwwroot/app.css
On Windows PowerShell:
& ".\.shellui\bin\tailwindcss.exe" -i "wwwroot/input.css" -o "wwwroot/app.css"dotnet build runs the MSBuild target. Link the generated stylesheet from the Blazor host:
<link href="~/app.css" rel="stylesheet" />Use npm when the project already has a Node.js toolchain or needs npm-based Tailwind integrations.
npm install -D tailwindcss@4.3.2 @tailwindcss/cli@4.3.2
Tailwind v4 does not require a separate initialization command. Create or edit wwwroot/input.css directly:
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));Tailwind v4 can discover source files from the project. If a JavaScript config is required for compatibility or plugins, load it explicitly from the CSS entry point:
@import "tailwindcss";
@config "../tailwind.config.js";Place a JavaScript config at the project root when using that example. Keep the theme variables and @theme inline mappings in the CSS entry point.
npx @tailwindcss/cli -i wwwroot/input.css -o wwwroot/app.css
Minify release output with:
npx @tailwindcss/cli -i wwwroot/input.css -o wwwroot/app.css --minify
For MSBuild, create a target that invokes the package:
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<NpmExecutable>npx</NpmExecutable>
<TailwindInputCss Condition="'$(TailwindInputCss)' == ''">$(MSBuildProjectDirectory)\wwwroot\input.css</TailwindInputCss>
<TailwindOutputCss Condition="'$(TailwindOutputCss)' == ''">$(MSBuildProjectDirectory)\wwwroot\app.css</TailwindOutputCss>
<TailwindMinify Condition="'$(Configuration)' == 'Release'">--minify</TailwindMinify>
<TailwindMinify Condition="'$(Configuration)' != 'Release'"></TailwindMinify>
</PropertyGroup>
<Target Name="BuildTailwindCSS" BeforeTargets="BeforeBuild" Condition="Exists('$(TailwindInputCss)')">
<Message Importance="high" Text="Building Tailwind CSS with @tailwindcss/cli..." />
<Exec Command="$(NpmExecutable) @tailwindcss/cli -i "$(TailwindInputCss)" -o "$(TailwindOutputCss)" $(TailwindMinify)" />
<Message Importance="high" Text="Tailwind CSS built successfully!" />
</Target>
</Project>Use one Tailwind build path per project: either the standalone target or the npm target. Running both can produce competing writes to wwwroot/app.css.
The browser build is useful for a quick prototype only:
<head>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.2"></script>
</head>It does not replace a version-pinned local build for production. Keep the application's theme variables and component CSS available when testing a prototype.
After setup:
dotnet build
Check that:
wwwroot/app.csscontains generated utilities.- The host includes the generated stylesheet.
- A Razor component using a ShellUI utility is styled in the browser.
- The standalone executable is in
~/.shellui/bin(%USERPROFILE%\.shellui\binon Windows), or in the project's.shellui/binif you put one there. - The npm project can run
npx @tailwindcss/cli -i wwwroot/input.css -o wwwroot/app.css.
- Confirm
wwwroot/input.csscontains@import "tailwindcss";. - Confirm the standalone executable is in
~/.shellui/bin(orSHELLUI_CACHE_DIR). If the build warns that it couldn't download it, save the file it names there. - Confirm
Build/ShellUI.targetsis imported by the project. - Confirm the input and output paths exist.
- For npm, confirm
tailwindcss@4.3.2and@tailwindcss/cli@4.3.2are installed and runnpx @tailwindcss/cli --help.
- Confirm
app.cssis linked from the Blazor host. - Rebuild after changing
input.cssor Razor markup. - Clear the browser cache while testing.
- Check the browser console for missing JavaScript assets separately from CSS generation.
- Use Tailwind
4.3.2for both the standalone download and the npm packages. - Use
@import "tailwindcss";, not the v3 layer imports. - Use
npx @tailwindcss/cliwith the version-pinned packages and CSS entry point.
Tailwind v4 themes are CSS-first. Keep the color variables in input.css, then map them into Tailwind with @theme inline:
@import "tailwindcss";
:root {
--background: oklch(0.99 0 0);
--foreground: oklch(0 0 0);
--primary: oklch(0.55 0.22 264.53);
--primary-foreground: oklch(1 0 0);
--radius: 0.5rem;
}
.dark {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--primary: oklch(0.81 0.17 75.35);
--primary-foreground: oklch(0 0 0);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--radius-lg: var(--radius);
}A theme tool such as tweakcn can provide a replacement :root and .dark block. Paste the generated variables into input.css, then rebuild Tailwind.
For fonts, use a project-local stylesheet or a font provider and retain fallbacks:
:root {
--font-sans: 'Custom Sans', ui-sans-serif, system-ui, sans-serif;
--font-mono: 'Custom Mono', ui-monospace, monospace;
}- Initialize the project with
shellui init. - Choose the standalone or npm Tailwind method.
- Add components with
shellui add. - Customize the variables in
wwwroot/input.css. - Build the project and verify the generated stylesheet.
Useful references: