Slotty 0.0.0-alpha.0.4

This is a prerelease version of Slotty.
There is a newer version of this package available.
See the version list below for details.
dotnet add package Slotty --version 0.0.0-alpha.0.4
                    
NuGet\Install-Package Slotty -Version 0.0.0-alpha.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Slotty" Version="0.0.0-alpha.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Slotty" Version="0.0.0-alpha.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Slotty" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Slotty --version 0.0.0-alpha.0.4
                    
#r "nuget: Slotty, 0.0.0-alpha.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Slotty@0.0.0-alpha.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Slotty&version=0.0.0-alpha.0.4&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Slotty&version=0.0.0-alpha.0.4&prerelease
                    
Install as a Cake Tool

🎯 Slotty

<div align="center">

Slotty Logo

A modern, flexible content slot system for ASP.NET Core that replaces the limitations of @RenderSection

NuGet Version NuGet Downloads Build Status License .NET

</div>


🚀 Why Slotty?

Tired of the rigid, error-prone @RenderSection system? Slotty brings modern content management to ASP.NET Core with a flexible, component-based approach that just works.

The Problem with @RenderSection

// ❌ Old way: Rigid, error-prone, limited
@RenderSection("Scripts", required: false)
@RenderSection("Styles", required: false)

// Must define sections in exact layout hierarchy
// No dynamic content injection
// Poor error handling
// Limited extensibility

The Slotty Solution


<slot name="head"></slot>
<slot name="scripts"></slot>


<slot name="sidebar">
    <div>Default sidebar content</div>
</slot>

✨ Features

  • 🎯 Multiple Content Sources - Add content to slots from anywhere in your application
  • 🔧 Slot Extensions - Automatic :before and :after extension points
  • 🛡️ Type Safety - Built-in validation with helpful error messages
  • 🎨 Development Tools - Visual slot debugging in development mode
  • 📦 Zero Configuration - Works out of the box with sensible defaults
  • 🚀 High Performance - Request-scoped content management
  • 🔄 Backward Compatible - Migrate gradually from @RenderSection

📋 Table of Contents

📦 Installation

Package Manager Console

Install-Package Slotty

.NET CLI

dotnet add package Slotty

PackageReference

<PackageReference Include="Slotty" Version="1.0.0" />

⚡ Quick Start

1. Register Services

// Program.cs
builder.Services.AddSlotty();
app.UseSlotty(); // For automatic dev tools injection

2. Define Slots in Layout


<!DOCTYPE html>
<html>
<head>
    <slot name="head">
        
        <title>Default Title</title>
    </slot>
</head>
<body>
    <header>
        <slot name="header"></slot>
    </header>
    
    <main>
        @RenderBody()
    </main>
    
    <slot name="scripts"></slot>
</body>
</html>

3. Fill Slots from Views


<fill slot="head">
    <title>Home Page</title>
    <meta name="description" content="Welcome to our site">
</fill>

<fill slot="header">
    <nav>Navigation content</nav>
</fill>

<h1>Welcome!</h1>

<fill slot="scripts">
    <script src="~/js/home.js"></script>
</fill>

⚙️ Configuration

Basic Configuration

// Use default settings (recommended)
builder.Services.AddSlotty();

Advanced Configuration

// Program.cs - Programmatic configuration
builder.Services.AddSlotty(options =>
{
    options.ValidationMode = SlottyValidationMode.Log; // Silent, Log, Throw
    options.DevToolsInjection = SlottyDevToolsInjectionMode.Auto; // Auto, Always, Never
});

Configuration via appsettings.json

{
  "Slotty": {
    "ValidationMode": "Log",
    "DevToolsInjection": "Auto"
  }
}
// Program.cs
builder.Services.AddSlotty(builder.Configuration.GetSection("Slotty"));

Validation Modes

Mode Description Use Case
Silent Basic slot name validation only Production environments
Log Validation with warning logs Staging/testing environments
Throw Strict validation with exceptions Development environments

📖 Basic Usage

Simple Slots


<slot name="sidebar"></slot>


<fill slot="sidebar">
    <div class="widget">Content here</div>
</fill>

Slots with Fallbacks


<slot name="breadcrumbs">
    <nav>
        <a href="/">Home</a>
    </nav>
</slot>


<fill slot="breadcrumbs">
    <nav>
        <a href="/">Home</a> > 
        <a href="/products">Products</a> > 
        <span>iPhone</span>
    </nav>
</fill>

Multiple Content Blocks


<fill slot="styles">
    <link rel="stylesheet" href="~/css/components.css">
</fill>

<fill slot="styles">
    <link rel="stylesheet" href="~/css/page-specific.css">
</fill>


<slot name="styles"></slot>

Slot Extensions

Every slot automatically gets :before and :after extension points:


<slot name="content"></slot>


<fill slot="content:before">
    <div class="alert">Important notice!</div>
</fill>

<fill slot="content">
    <h1>Main Content</h1>
</fill>

<fill slot="content:after">
    <div class="related-links">Related: ...</div>
</fill>

🔥 Advanced Examples

Dynamic E-commerce Layout


<!DOCTYPE html>
<html>
<head>
    <slot name="head">
        <title>My Store</title>
    </slot>
    <slot name="meta"></slot>
</head>
<body>
    <header>
        <slot name="header:before"></slot>
        <slot name="navigation"></slot>
        <slot name="header:after"></slot>
    </header>
    
    <div class="container">
        <aside>
            <slot name="sidebar">
                <div>Default sidebar</div>
            </slot>
        </aside>
        
        <main>
            <slot name="content:before"></slot>
            @RenderBody()
            <slot name="content:after"></slot>
        </main>
    </div>
    
    <footer>
        <slot name="footer"></slot>
    </footer>
    
    <slot name="scripts:before"></slot>
    <slot name="scripts"></slot>
    <slot name="scripts:after"></slot>
</body>
</html>

Product Page with Rich Content


<fill slot="head">
    <title>@Model.Name - My Store</title>
</fill>

<fill slot="meta">
    <meta name="description" content="@Model.Description">
    <meta property="og:title" content="@Model.Name">
    <meta property="og:image" content="@Model.ImageUrl">
</fill>

<fill slot="header:before">
    <div class="sale-banner">🔥 Flash Sale: 50% Off!</div>
</fill>

<fill slot="navigation">
    <nav>
        <a href="/">Home</a> > 
        <a href="/products">Products</a> > 
        @Model.Category.Name
    </nav>
</fill>

<fill slot="sidebar">
    <div class="filters">
        <h3>Filter Products</h3>
        
    </div>
    
    <div class="recent-products">
        <h3>Recently Viewed</h3>
        
    </div>
</fill>


<div class="product-details">
    <h1>@Model.Name</h1>
    <div class="price">$@Model.Price</div>
    
</div>

<fill slot="content:after">
    <section class="related-products">
        <h2>You Might Also Like</h2>
        
    </section>
    
    <section class="reviews">
        <h2>Customer Reviews</h2>
        
    </section>
</fill>

<fill slot="scripts">
    <script src="~/js/product-gallery.js"></script>
    <script src="~/js/add-to-cart.js"></script>
</fill>

Conditional Content with View Components


<fill slot="sidebar:before">
    @await Component.InvokeAsync("ShoppingCart")
</fill>

<fill slot="footer">
    @if (User.Identity.IsAuthenticated)
    {
        @await Component.InvokeAsync("UserAccount")
    }
    else
    {
        @await Component.InvokeAsync("LoginPrompt")
    }
</fill>

Partial Views with Slots


<div class="product-card">
    <slot name="product-image">
        <img src="@Model.DefaultImage" alt="@Model.Name">
    </slot>
    
    <div class="product-info">
        <h3>@Model.Name</h3>
        <div class="price">$@Model.Price</div>
        
        <slot name="product-actions">
            <button class="btn btn-primary">Add to Cart</button>
        </slot>
    </div>
    
    <slot name="product-badges"></slot>
</div>


@Html.Partial("_ProductCard", product)

<fill slot="product-badges">
    @if (product.IsOnSale)
    {
        <span class="badge sale">SALE</span>
    }
</fill>

<fill slot="product-actions">
    <button class="btn btn-primary" data-product="@product.Id">
        Quick Add - $@product.Price
    </button>
    <button class="btn btn-secondary">
        <i class="heart"></i> Wishlist
    </button>
</fill>

🛠️ Development Tools

Automatic Dev Tools

In development mode, Slotty automatically injects visual debugging tools:


<style>
    .slotty-slot-wrapper { border: 2px dashed #007bff; margin: 2px; }
    .slotty-slot-label { background: #007bff; color: white; font-size: 12px; }
</style>

<script>
    // Interactive slot debugging
    console.log('Slotty dev tools loaded');
</script>

Head-Safe Debugging

Slots in <head> use HTML comments for valid markup:

<head>
    
    <title>My Page</title>
    <meta charset="utf-8">
    
</head>

Configuration

// Control dev tools injection
builder.Services.AddSlotty(options =>
{
    options.DevToolsInjection = SlottyDevToolsInjectionMode.Always; // Always show
    // or SlottyDevToolsInjectionMode.Never;  // Never show
    // or SlottyDevToolsInjectionMode.Auto;   // Development only (default)
});

🔄 Migration Guide

From @RenderSection

Before:


@RenderSection("Scripts", required: false)
@RenderSection("Styles", required: false)


@section Scripts {
    <script src="~/js/page.js"></script>
}

@section Styles {
    <link rel="stylesheet" href="~/css/page.css">
}

After:


<slot name="scripts"></slot>
<slot name="styles"></slot>


<fill slot="scripts">
    <script src="~/js/page.js"></script>
</fill>

<fill slot="styles">
    <link rel="stylesheet" href="~/css/page.css">
</fill>

Benefits of Migration

@RenderSection Slotty Benefit
Single content per section Multiple fills per slot ✅ Flexible content composition
Must be defined in hierarchy Fill from anywhere ✅ True component architecture
Required/optional only Rich validation modes ✅ Better error handling
No extensibility :before and :after extensions ✅ Built-in extensibility
No default content Fallback content support ✅ Progressive enhancement

📚 API Reference

TagHelpers

<slot>

Defines a content slot that can be filled by <fill> tags.

Attributes:

  • name (required): The unique name of the slot

Example:

<slot name="sidebar">
    <div>Default content</div>
</slot>
<fill>

Adds content to a named slot.

Attributes:

  • slot (required): The name of the slot to fill

Example:

<fill slot="sidebar">
    <div>Custom sidebar content</div>
</fill>

Configuration

SlottyOptions
Property Type Default Description
ValidationMode SlottyValidationMode Silent Validation behavior
DevToolsInjection SlottyDevToolsInjectionMode Auto Dev tools injection mode
SlottyValidationMode
Value Description
Silent Basic validation only
Log Validation with warning logs
Throw Strict validation with exceptions
SlottyDevToolsInjectionMode
Value Description
Auto Inject in development environment only
Always Always inject dev tools
Never Never inject dev tools

Service Registration

// Basic registration
services.AddSlotty();

// With configuration
services.AddSlotty(options => { /* configure */ });

// From configuration section
services.AddSlotty(configuration.GetSection("Slotty"));

Middleware Registration

// Enable automatic dev tools injection
app.UseSlotty();

🤝 Contributing

We love contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/AaronLayton/slotty.git
cd slotty
dotnet restore
dotnet build
dotnet test

Running Examples

dotnet run --project Slotty.Example

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🌟 Support


<div align="center">

Made with ❤️ by Aaron Layton • Follow on X

⬆ Back to Top

</div>

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

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
1.1.0 548 7/22/2025
1.0.2 167 7/16/2025
0.0.0-alpha.0.4 121 7/16/2025

See CHANGELOG.md for detailed release notes