Slots
Slots are a core feature of TailwindVariants.NET that allow you to define reusable, named “buckets” of classes for your components. They give you fine-grained control over styling specific parts of a component, without hardcoding CSS strings.
Think of a slot as a strongly-typed placeholder in a component that you can populate with different styles.
Why Slots?
When building components, you often need to style different parts separately:
<button class="px-4 py-2 rounded bg-blue-500 text-white">
<span class="font-semibold">Click me</span>
</button>
Here, the outer <button> and the inner <span> require different styles. Using slots, you can define these parts declaratively, and apply variants safely:
- ✅ Strongly typed — no more guessing class names.
- ✅ Flexible — style each part of a component independently.
- ✅ Integrates with variants — combine slots and variants for full customization.
- ✅ Compile-time helpers — thanks to source generators.
Defining Slots
A slot is defined as a nested class inside a component that implements ISlots:
public sealed partial class Button : ISlotted<Button.Slots>
{
public sealed partial class Slots : ISlots
{
public string? Base { get; set; }
public string? Label { get; set; }
}
}
Here, Base represents the main container of the button, and Label represents the text inside it.
Using Slots
You map your slots with TvDescriptor and optionally use variants:
public static readonly TvDescriptor<Button, Slots> _button = new(
@base: "",
variants: new()
{
[b => b.Variant] = new Variant<Variants, Slots>()
{
[Variants.Primary] = new()
{
[s => s.Base] = "bg-blue-500 text-white",
[s => s.Label] = "font-semibold"
},
[Variants.Secondary] = new()
{
[s => s.Base] = "bg-gray-200 text-black",
[s => s.Label] = "font-medium"
}
}
}
);
Then in your component:
<button class="@_slots.GetBase()">
<span class="@_slots.GetLabel()">Click me</span>
</button>
The GetBase() and GetLabel() methods are generated by the source generator, ensuring type safety and discoverability.
Best Practices
- Use descriptive slot names — e.g.,
Base,Icon,Label. - Combine slots with variants for maximum flexibility.
- Avoid hardcoding classes in the markup — always use
_slots.Get{SlotName}(). - Define all slots inside the component class — it keeps them strongly typed and self-contained.
Slots, together with variants, allow TailwindVariants.NET to provide a fully type-safe and maintainable approach to styling Blazor components.