// CounterExample.razor.cs
[GenerateParameterMethods]
public partial record CounterParameters : HtmxComponentParameters
{
public int Count { get; init; } = 10;
public string Increment()
{
var parameters = this with { Count = Count + 1 };
return parameters.ToComponentUrl(HtmxRoutes.RouteCounter);
}
}
// HtmxRoutes.cs
public const string RouteCounter = "/ui/examples/counter";
// HtmxEndpointConfiguration.cs
app.MapHtmxGet<CounterExample, CounterParameters>(RouteCounter).AllowAnonymous();
// JsonSerializerContext.cs
[JsonSerializable(typeof(CounterParameters))]@inherits HtmxComponentBase<CounterParameters>
<div class="counter-section" id="counter-component">
<div class="grid">
<HtmxTag Element="button"
HxGet="@Parameters.Increment()"
HxSwap="@Hx.Swap.OuterHtml"
HxTarget="#counter-component">
+ Increment
</HtmxTag>
<input value="@Parameters.Count" readonly/>
</div>
</div>@inherits SimpleHtmxComponent<CounterState>
<div id="counter">
<div class="grid">
@HtmxBuilderExtensions.Button("+", Url(s => s with { Count = s.Count + 1 }), "counter")
<span>@State.Count</span>
@HtmxBuilderExtensions.Button("-", Url(s => s with { Count = s.Count - 1 }), "counter")
</div>
</div>
public record CounterState { public int Count { get; init; } = 0; }// Program.cs
services.AddFastComponentsAuto(); // Replaces manual service registration
app.UseFastComponentsAuto(); // Replaces manual endpoint mapping- ❌ No more separate
.razor.csfiles - ❌ No more
[GenerateParameterMethods]attributes - ❌ No more manual endpoint mapping
- ❌ No more JSON serialization registration
- ✅ Convention-based routing:
/htmx/counter - ✅ Auto-discovery of components
// Before: Verbose HtmxTag syntax
<HtmxTag Element="button" HxGet="/url" HxTarget="#target" HxSwap="outerHTML">
// After: Fluent builder
@HtmxBuilder.Button().GetSelf("/url", "target").Text("Click me")
// Or helper methods for common patterns
@HtmxBuilderExtensions.Button("Click me", "/url", "target")
@HtmxBuilderExtensions.SearchInput("/search", "#results")
@HtmxBuilderExtensions.LoadContainer("/load-content")// Common patterns made simple
HtmxPatterns.SelfUpdatingButton(url, id) // Button that updates itself
HtmxPatterns.SearchInput(url, target) // Search with debouncing
HtmxPatterns.LoadOnce(url) // Load content once on page load
// Smart defaults
HtmxDefaults.Swap // "outerHTML"
HtmxDefaults.SearchTrigger // "keyup changed delay:300ms"
HtmxDefaults.LoadOnceTrigger // "load once"// Before: Complex parameter methods
public string Increment()
{
var parameters = this with { Count = Count + 1 };
return parameters.ToComponentUrl(HtmxRoutes.RouteCounter);
}
// After: Simple lambda expressions
Url(s => s with { Count = s.Count + 1 }) // Much cleaner!
Url(new CounterState { Count = State.Count + 1 }) // Or explicit- Keep existing
HtmxComponentBase<T>API - Add new
SimpleHtmxComponent<T>alongside - Add convention-based registration as opt-in
- Migrate examples to simplified API
- Show performance/maintainability benefits
- Provide migration tooling
- Mark old API as
[Obsolete]but still supported - Focus documentation on simplified API
- Community feedback integration
- ✅ 5-minute setup - Add components, registration is automatic
- ✅ No magic - Clear, convention-based patterns
- ✅ Less to learn - Focus on HTMX concepts, not FastComponents boilerplate
- ✅ Less maintenance - Fewer files, less configuration
- ✅ Better debugging - Simpler call stacks, clearer errors
- ✅ Higher productivity - Build components faster
// Counter component
@HtmxBuilderExtensions.Button("+", Url(s => s with { Count = s.Count + 1 }), "counter")
// Search component
@HtmxBuilderExtensions.SearchInput("/search", "#results", "Search movies...")
// Auto-loading content
@HtmxBuilderExtensions.LoadContainer("/load-data", "Loading...")
// Form that posts to server
@HtmxBuilder.Form().PostTo("/submit", "#result").Content(@<input name="data" />)This simplified API maintains all the power of FastComponents while dramatically reducing complexity for developers!