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.

An unhandled error has occurred. Reload 🗙