Generic reusable Blazor UI components. Works with both Blazor Server and Blazor WebAssembly. Built on Radzen.Blazor.
Documentation: blazor.tharga.net
dotnet add package Tharga.BlazorRegister services in Program.cs:
builder.Services.AddThargaBlazor(o => o.Title = "My Application");You can also bind configuration from appsettings.json:
builder.Services.AddThargaBlazor(configuration: builder.Configuration);Or combine both (code overrides config):
builder.Services.AddThargaBlazor(o => o.Title = "My App", configuration: builder.Configuration);Configuration section in appsettings.json:
{
"Tharga": {
"Blazor": {
"Title": "Application Name"
}
}
}This registers:
BreadCrumbService(scoped)ILocalStorageServicefrom Blazored.LocalStorageIOptions<BlazorOptions>for configurationIBlazorLanguageProviderandLanguageResolver(scoped), both withTryAdd
Pre-built button components with busy states and error handling.
ActionButton— Wraps async click actions with automatic loading state, error notifications, and optional delay.StandardButton— Base button with typed styling (Normal,Discrete,Information,Warning,Error,Confirm,Reject).CancelButton— Pre-styled cancel button.CopyButton— Copies text to clipboard via JS interop with success notification.
Route-aware breadcrumb trail with programmatic control.
<BreadCrumbs />Use BreadCrumbService to customize the trail:
@inject BreadCrumbService BreadCrumbService
// Add a virtual segment
BreadCrumbService.AddVirtualSegment("Details", "/items/42");
// Convert a query parameter into a breadcrumb
BreadCrumbService.RegisterVirtualSegmentQueryParam("category");
// Relink, unlink or remove segments
BreadCrumbService.RelinkSegment("Items", "/items?status=active");
BreadCrumbService.UnlinkSegment("Current");
BreadCrumbService.RemoveSegment("Records");
// Show a readable name for an id segment, keeping its position and link
BreadCrumbService.SetSegmentText(caseId, "KS 2026-14");
// Re-render the trail, e.g. after a language change
BreadCrumbService.Refresh();Register an IBreadCrumbTextProvider to translate URL segments app-wide (cases → Ärenden). It is asked every time the trail is read; returning null keeps the default capitalised text. See the breadcrumbs article for details.
<CustomErrorBoundary>
<ChildContent>@Body</ChildContent>
</CustomErrorBoundary>Catches unhandled exceptions, logs them with a correlation ID, and displays an error view with recovery.
An UnauthorizedAccessException is treated as an expected outcome rather than a crash: it renders a compact Access denied panel carrying the exception message, and logs at Warning. Everything else renders the crash panel and logs at Error.
Exception messages and stack traces are shown only when the host opts in, so they never reach a production user:
builder.Services.AddThargaBlazor(o => o.ShowExceptionDetails = builder.Environment.IsDevelopment());ExpandableCard— Collapsible card with an optional leading icon or image, header menu, and local storage state persistence (AllowSaveState, keyed byStateKey).Loading— Indeterminate progress indicator (centered or inline).Title— Dynamic page title based on route andBlazorOptions.Title.DateTimeView— Date/time display: relative, absolute, or the day alone, with whatever the text leaves out as the tooltip. Renders in English or Swedish, and can recompute a relative label on an interval.TimeSpanView— Formatted time span display, in English or Swedish.
DateTimeView and TimeSpanView resolve their language from, in order: the Language parameter, an IBlazorLanguageProvider the host registered, BlazorOptions.Language, and CultureInfo.CurrentUICulture — falling back to English for a culture the Toolkit has no wording for.
builder.Services.AddThargaBlazor(o => o.Language = Language.Sv);Options are a singleton, so a multi-tenant site resolves language per circuit instead:
builder.Services.AddScoped<IBlazorLanguageProvider, TenantLanguageProvider>();A relative label describes a moving quantity but only recomputes when the component renders, so in a static grid it goes stale. Display="EDateTimeDisplay.Absolute" (or Date, for narrow columns) avoids the problem entirely, and RefreshInterval opts into recomputing it. See Date and duration views.
- .NET 9
- .NET 10
dotnet build -c Release
dotnet test -c ReleaseMIT