Small, composable Blazor component base classes for libraries that need clean defaults without buying into a UI framework.
Lepton gives component authors a consistent foundation for child content, element attributes, IDs, async disposal, and cancellation. It is not a component library. It is the base layer you build component libraries on.
- Pick exactly the component capabilities you need.
- Keep
class,style, and unmatched attributes consistent across components. - Get disposal and cancellation patterns without rewriting them in every base class.
- Type against matching interfaces when you need capability-based APIs.
dotnet add package Soenneker.Lepton.Suite| Need | Use |
|---|---|
| Plain Blazor base | LeptonComponent |
| Child content | LeptonContent |
| Element attributes | LeptonElement |
| Child content + element attributes | LeptonContentElement |
| Id + child content + element attributes | LeptonIdentifiableContentElement |
| Async disposal | LeptonDisposable |
| Disposable content | LeptonDisposableContent |
| Disposable content element | LeptonDisposableContentElement |
| Disposable identifiable content element | LeptonDisposableIdentifiableContentElement |
| Disposal-bound cancellation | LeptonCancellable |
| Cancellable content element | LeptonCancellableContentElement |
| Cancellable identifiable content element | LeptonCancellableIdentifiableContentElement |
Every public base has a matching interface in Soenneker.Lepton.Suite.Abstract.
Element bases expose Class, Style, and AdditionalAttributes, then build render-ready attributes for you.
public sealed class Card : LeptonContentElement
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "section");
builder.AddMultipleAttributes(1, BuildAttributes("data-slot", "card"));
builder.AddContent(2, ChildContent);
builder.CloseElement();
}
}<Card Class="card" style="padding: 1rem" data-state="open">
Content
</Card>class and style values are merged instead of clobbered.
Disposable bases expose ThrowIfDisposed() and track disposal state.
public abstract class ModuleBackedComponent : LeptonDisposable
{
private IAsyncDisposable? _module;
public override async ValueTask DisposeAsync()
{
if (_module is not null)
await _module.DisposeAsync();
await base.DisposeAsync();
}
}Cancellable bases cancel their token during DisposeAsync().
public abstract class LoadingComponent : LeptonCancellable
{
protected Task Load()
{
ThrowIfDisposed();
return Task.Delay(TimeSpan.FromSeconds(1), CancellationToken);
}
}Cancellable types are an add-on over disposable shapes:
LeptonDisposableContentElement
-> LeptonCancellableContentElement
LeptonDisposableIdentifiableContentElement
-> LeptonCancellableIdentifiableContentElement
So if you choose a cancellable element, you still get the disposable element behavior underneath it.
AdditionalAttributesis the unmatched-attribute parameter for element bases.- Identifiable element bases add
idwhenIdis set. - Cancellable bases expose a protected
CancellationToken. - Base classes are abstract and intended for component-library authors.
