-
-
Notifications
You must be signed in to change notification settings - Fork 540
Description
Blazorise Version
2.0.2
What Blazorise provider are you running on?
Bootstrap5
Link to minimal reproduction or a simple code snippet
Description contains steps to reproduce. Dont think a repro repo is really needed. If so let me know.
Steps to reproduce & bug description
When using Select<TValue> with a nullable TValue (e.g. TodoItemStatus?), selecting a SelectItem that has Value="null" does not trigger ValueChanged. This makes it impossible to use null as a valid selectable value, which is a common pattern for "All" / "None" / reset options.
Nullable types are documented as supported
The official documentation explicitly states:
SelectandSelectItemare generic components and they support all of the basic value types line int, string, enum, etc. Nullable types are also supported.
Additionally, the SelectItem API documentation lists Value with a default of null, confirming that null is intended to be a valid value.
As a consumer, the natural expectation when reading "nullable types are supported" is that a SelectItem with Value="null" works as a selectable option. This is the standard pattern for "All" / "None" / "Reset" entries in dropdowns. Currently, nullable types are only partially supported — you can bind a nullable type, but you cannot select back to null once a non-null value has been chosen.
Prior issue
This was previously reported in #2921 (Sep 2021) and closed with a workaround recommendation. However, the underlying root cause was never fixed, and the documentation continues to advertise nullable type support without mentioning this limitation.
Steps to reproduce
<Select TValue="TodoItemStatus?" Value="@_status" ValueChanged="@OnStatusChanged">
<SelectItem TValue="TodoItemStatus?" Value="null">All</SelectItem>
<SelectItem TValue="TodoItemStatus?" Value="TodoItemStatus.NotStarted">Not Started</SelectItem>
<SelectItem TValue="TodoItemStatus?" Value="TodoItemStatus.InProgress">In Progress</SelectItem>
<SelectItem TValue="TodoItemStatus?" Value="TodoItemStatus.Completed">Completed</SelectItem>
</Select>
@code {
private TodoItemStatus? _status;
private Task OnStatusChanged(TodoItemStatus? value)
{
_status = value; // never called when selecting "All"
return Task.CompletedTask;
}
}- Select "In Progress" →
ValueChangedfires ✅ - Select "All" (null) →
ValueChangeddoes not fire ❌
Root cause
The issue is in SelectItem.razor.cs:
protected string StringValue => Value?.ToString();When Value is null, StringValue returns null. Blazor omits HTML attributes with null values, so the rendered <option> has no value attribute:
<!-- Rendered HTML -->
<option>All</option>
<!-- Expected -->
<option value="">All</option>Per the HTML spec, an <option> without a value attribute uses its text content as the value. So when the user selects "All", the browser sends "All" instead of "".
This causes the following chain in BaseInputComponent.CurrentValueHandler:
string.IsNullOrEmpty("All")→false→ does not enter theDefaultValuebranchParseValueFromStringAsync("All")is calledConverters.TryChangeType<TodoItemStatus?>("All")→ fails (not a valid enum name)result.Successisfalse→SetCurrentValueAsyncis never calledValueChangednever fires
Suggested fix
⚠️ Note: This suggested fix is AI-generated and has not been validated. It may require further review and testing.
In SelectItem.razor.cs, ensure StringValue always returns a non-null string so the value attribute is rendered:
// Before
protected string StringValue => Value?.ToString();
// After
protected string StringValue => Value?.ToString() ?? string.Empty;This ensures <option value=""> is rendered for null values. The empty string then correctly triggers the string.IsNullOrEmpty check in CurrentValueHandler, which sets DefaultValue (null for nullable types) and fires ValueChanged.
Current workaround
Use Select<string> instead and manually parse the enum:
<Select TValue="string" Value="@_statusValue" ValueChanged="@OnStatusChanged">
<SelectItem TValue="string" Value="@string.Empty">All</SelectItem>
@foreach (var status in Enum.GetValues<TodoItemStatus>())
{
<SelectItem TValue="string" Value="@status.ToString()">@status</SelectItem>
}
</Select>
@code {
private string _statusValue = string.Empty;
private Task OnStatusChanged(string value)
{
_statusValue = value;
var parsed = Enum.TryParse<TodoItemStatus>(value, out var s) ? s : (TodoItemStatus?)null;
return Task.CompletedTask;
}
}This workaround is functional but forces consumers to abandon the generic nullable type support that is explicitly documented. It introduces manual string-to-enum conversion boilerplate that should not be necessary.
What is expected?
One of the following should happen:
- Fix the bug: Apply the suggested fix (or an equivalent) so that
SelectItemwith anullvalue works correctly, as the documentation promises. - Remove nullable support from the documentation: If nullable
SelectItemvalues are not intended to work, remove the "Nullable types are also supported" statement from the docs to avoid misleading consumers. - Document the limitation: At a minimum, add a visible note to the Select documentation that clarifies: while nullable
TValuebinding is supported, selecting back tonullvia aSelectItemwithValue="null"does not work, and a workaround is required.
What is actually happening?
See description.
What browsers do you see the problem on?
No response
Any additional comments?
No response