I am trying to render a custom radio button in Blazor only adding a default css class to the component. So I thought I could just extend the InputRadio component and modify the css classes that are defined.
So I have a css class called "foo" and Im trying to make a custom component FooRadio by default have all the stuff with InputRadio but also class="foo". I dont want to have to actually add it manually.
I tried doing this..
@inherits InputRadio<TValue>
@{
base.BuildRenderTree(__builder);
}
Now I thought there may have been a Css property I could tap into and overwrite, but I dont seem to have access to one. The InputRadio does merge the AdditionalAttributes with the Context.FieldCss, but the only thing available for me is the AdditionalAttributes and it is a ReadOnly Dictionary. Also InputRadio requires a TValue, and I am not sure how to inherit it and also give it a TValue. I assume my custom Radio Button will need to have a as well.
So, I started just building a simple <input type="radio".../> but I dont know all the callbacks or bindings I will need to add in the component to make it function like the InputRadio.
I know InputRadio requires you to be inside an InputRadioGroup which is fine. Ideally Id like to be able to do something like this..
<InputRadioButtonGroup>
<InputRadio...>
<FooRadio...>
<InputRadio...>
</InputRadioButtonGroup>
Again, FooRadio and InputRadio will act the same. Its just FooRadio will have a css class of "foo" without actually declaring it on the FooRadio tag
Hope this is enough info. If not, I can give more info. Maybe I am approaching this in a much more complicated way than needs to be.
Thank you for any assistance.
InputRadioGroup
and InputRadio
are implemented in a slightly different way to most InputBase<TValue>
controls. This makes them harder to customize without building new versions based on the original codebase.
InputRadioGroup
is a component with no UI output: the class attribute has no effect. It provides a wrapper context for the InputRadio
child instances that manages state and cascades an InputRadioContext
.
The Css for each InputRadio
is based on the value provided in the class
attribute and some colour formatting based on validation information in the EditContext
.
So to achieve what you want, we need to create a CustomInputRadio
component that wraps an instance of InputRadio
rather than inheriting from it.
Here's an example that applies the standard Bootstrap formatting.
@typeparam TValue
<div class="form-check">
<InputRadio class="@this.CssClass" TValue="TValue" Name="ContinentGroup" Value="Value" />
<label class="@this.LabelCssClass">
@_label
</label>
</div>
@code {
[Parameter] public TValue? Value { get; set; }
[Parameter] public string? Label { get; set; }
[Parameter] public string CssClass { get; set; } = "form-check-input";
[Parameter] public string LabelCssClass { get; set; } = "form-check-label";
private string? _label => this.Label ?? Value?.ToString();
}
Which you then use like this:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
<EditForm EditContext="_editContext">
<InputRadioGroup Name="ContinentGroup" @bind-Value="_model.Value">
@foreach (var continent in _continents)
{
<CustomInputRadio Value="continent" />
}
</InputRadioGroup>
</EditForm>
<div class="bg-dark text-white m-2 p-2">
<pre>Value: @_model.Value</pre>
</div>
@code {
private EditContext? _editContext;
private Model _model = new();
protected override void OnInitialized()
{
_editContext = new(_model);
}
private List<String> _continents = new() { "Europe", "Oceania", "Africa" };
public class Model
{
public string? Value { get; set; }
}
}
You can find the source code here - https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web/src/Forms/InputRadio.cs
If you want to build and combine strings into Css strings see how to create a CssBuilder utility - https://github.com/EdCharbeneau/BlazorComponentUtilities