TailwindVariants.NET
0.2.8
dotnet add package TailwindVariants.NET --version 0.2.8
NuGet\Install-Package TailwindVariants.NET -Version 0.2.8
<PackageReference Include="TailwindVariants.NET" Version="0.2.8" />
<PackageVersion Include="TailwindVariants.NET" Version="0.2.8" />
<PackageReference Include="TailwindVariants.NET" />
paket add TailwindVariants.NET --version 0.2.8
#r "nuget: TailwindVariants.NET, 0.2.8"
#:package TailwindVariants.NET@0.2.8
#addin nuget:?package=TailwindVariants.NET&version=0.2.8
#tool nuget:?package=TailwindVariants.NET&version=0.2.8
TailwindVariants.NET
TailwindVariants.NET is a strongly typed Blazor library for managing TailwindCSS variants and slot-based styling.
⚠️ This package is not related to
tailwind-variants— it only draws inspiration from its ideas and applies them to a strongly typed, Blazor-first API.
✨ Features
- Strongly typed variant definitions for Blazor components (with or without slots).
- Default classes for slots + variants, and slot-aware compound variants.
- Generated slot accessors for convenient, strongly typed access to slot classes (
b => b.Baseautomatically wrapped). - Simple API builder (
Variants<TOwner, TSlots>). - Integration with
TailwindMerge.NETto resolve conflicts between Tailwind classes. - Lightweight, no JS runtime dependencies (pure Blazor/C#).
- Incremental source generator (
TailwindVariants.SourceGenerators) for generating strongly typed slot accessors. - Supports .NET 8, .NET 9, and .NET Standard 2.0 (source generator only).
- Works seamlessly in Blazor projects (Server, WebAssembly, Hybrid).
Installation
Install from NuGet:
dotnet add package TailwindVariants.NET
To enable automatic generation of slot accessors, it's included an analyzer with the main package.
The package supports:
- >= .NET 8
Quick Example
using TailwindVariants.NET;
public partial class Button : ISlottable<Button.Slots>
{
private static readonly TvDescriptor<Button, Slots> _button = new
(
@base: "font-semibold border rounded",
variants: new()
{
[b => b.Variant] = new Variant<Variants, Slots>()
{
[Variants.Primary] = "bg-blue-500 text-white border-transparent",
[Variants.Secondary] = "bg-white text-gray-800 border-gray-400",
},
[b => b.Size] = new Variant<Sizes, Slots>()
{
[Sizes.Small] = "text-sm py-1 px-2",
[Sizes.Medium] = "text-base py-2 px-4",
},
}
compoundVariants:
[
new(b => b.Variant == Variants.Primary && !b.Disabled)
{
Class = "hover:bg-blue-600"
}
]
);
protected override void OnParametersSet()
{
_slots = Tv.Invoke(this, _button);
}
protected override TvDescriptor<Button, Slots> GetDescriptor() => _button;
public sealed partial class Slots : ISlots
{
public string? Base { get; set; }
}
// ... enums omitted for brevity ...
}
In the component:
@inherits TwComponentBase<Button, Button.Slots>
<button class="@_slots.GetBase()" disabled="@Disabled">
@ChildContent
</button>
@code
{
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public Slots? Classes { get; set; }
[Parameter]
public Variants Variant { get; set; }
[Parameter]
public Sizes Size { get; set; }
[Parameter]
public bool Disabled { get; set; }
}
Slot Access
With generated slot accessors (via the source generator), you no longer need to write _slots[b => b.Avatar] manually.
You can use strongly typed properties:
<img class="@_slots.GetBase()" src="avatar.png" />
<p class="@_slots.GetDescription()">Description text</p>
This is enabled by the incremental source generator (TailwindVariants.SourceGenerators), which automatically generates accessors for each component that implements ISlots.
Documentation
Go to the documentation for the full explanation of the example
Acknowledgements / Credits
Special thanks to the authors of the following projects that are either used or inspired this work:
- tailwind-variants (jrgarciadev) — for the general concept of variants & compound variants.
- tailwind-merge-dotnet (desmondinho) — Tailwind class merge utilities.
Check out those projects for more tools and context.
Contributing
Contributions are always welcome!
Please follow our contributing guidelines.
Please adhere to this project's CODE_OF_CONDUCT.
License
MIT — see the LICENSE file in the repository.
Repository & Issues
If you encounter problems or have feature requests, open an issue on the GitHub repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Logging (>= 9.0.9)
- TailwindMerge.NET (>= 1.0.0)
-
net9.0
- Microsoft.Extensions.Logging (>= 9.0.9)
- TailwindMerge.NET (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.8 | 354 | 11/21/2025 |
| 0.2.8-preview.1 | 138 | 11/5/2025 |
| 0.2.7 | 187 | 10/26/2025 |
| 0.2.7-preview.4 | 78 | 10/24/2025 |
| 0.2.7-preview.3 | 127 | 10/23/2025 |
| 0.2.7-preview.2 | 133 | 10/23/2025 |
| 0.2.7-preview.1 | 125 | 10/20/2025 |
| 0.2.6 | 115 | 10/17/2025 |
| 0.2.5 | 122 | 10/17/2025 |
| 0.2.4 | 332 | 10/16/2025 |
| 0.2.3 | 167 | 10/16/2025 |
| 0.2.2 | 171 | 10/15/2025 |
| 0.2.1 | 175 | 10/14/2025 |
| 0.2.0 | 164 | 10/14/2025 |
| 0.1.0 | 331 | 10/12/2025 |
| 0.0.6 | 121 | 10/11/2025 |
| 0.0.5 | 111 | 10/11/2025 |
| 0.0.4 | 124 | 10/10/2025 |
| 0.0.3 | 119 | 10/10/2025 |
| 0.0.2 | 160 | 10/3/2025 |
| 0.0.1 | 181 | 10/2/2025 |