In this lesson, you will learn how to build reusable, custom form controls in Blazor that seamlessly integrate with standard data binding and validation systems.
The Power of InputBase<T>
While Blazor provides standard inputs like <InputText> and <InputNumber>, you often need unique UI components, such as a custom star-rating selector or a masked input field. To make these work with Blazor's form infrastructure (like <EditForm>), you don't build from scratch; you inherit from the InputBase<T> class.
By inheriting from InputBase<T>, your component automatically gains the ability to participate in EditContext validation, CSS class management for error states, and two-way @bind-Value support.
Implementation Pattern
The core of your component revolves around the Value property and the ValueChanged event. You must call CurrentValueAsString or use Value directly to ensure the parent form stays in sync with your component's internal state.
Here is a simplified example of a custom checkbox-style toggle:
@inherits InputBase<bool>
<div class="toggle-container @(CurrentValue ? "on" : "off")"
@onclick="Toggle">
@(CurrentValue ? "Enabled" : "Disabled")
</div>
@code {
private void Toggle() => CurrentValue = !CurrentValue;
protected override bool TryParseValueFromString(string value, out bool result, out string validationErrorMessage)
=> throw new NotImplementedException();
}
Key Considerations
ValuevsCurrentValue: When you update your component’s internal state, updateCurrentValue. This property automatically triggers theValueChangedevent and marks the field as "modified" within theEditContext, which is essential for validation.- CSS Integration:
InputBase<T>provides anEditContextthat automatically tracks validation status. You can accessCssClassto appendis-invalidoris-validstyles to your custom HTML elements automatically based on whether the form state is valid. - Parsing: If your input handles complex types, you must override
TryParseValueFromString. For simple toggles or booleans, you can often leave this unused, provided you handle the logic viaCurrentValue.
By extending InputBase<T>, you ensure your custom components behave exactly like native Blazor inputs, maintaining consistency across your application's forms.
Key Takeaway: By inheriting from InputBase<T>, you bridge your custom UI logic with Blazor’s validation and binding systems, allowing your unique components to function as first-class citizens in any EditForm.