diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor index 7dfe510d4c..abde090255 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor @@ -12,12 +12,50 @@ var searchBoxClearIconCss = BitIconInfo.From(SearchBoxClearIcon, SearchBoxClearIconName ?? "Cancel")?.GetCssClasses(); var comboBoxAddButtonIconCss = BitIconInfo.From(ComboBoxAddButtonIcon, ComboBoxAddButtonIconName ?? "Add")?.GetCssClasses(); var itemCheckIconCss = GetItemCheckIconCss(); + + RenderFragment emptyContent = + @
+ @if (HasSearchText && (NoResultsTemplate is not null || NoResultsText.HasValue())) + { + @if (NoResultsTemplate is not null) + { + @NoResultsTemplate + } + else + { + @NoResultsText + } + } + else if (EmptyTemplate is not null) + { + @EmptyTemplate + } + else + { + @(EmptyText ?? (HasSearchText ? "No results found" : "No items found")) + } +
; + + RenderFragment loadingContent = + @
+ @if (LoadingTemplate is not null) + { + @LoadingTemplate + } + else + { +
+ @(LoadingText ?? "Loading...") + } +
; } -@if (Virtualize && (Options ?? ChildContent) is not null) +@if ((Virtualize || IsLoading) && (Options ?? ChildContent) is not null) { - @* In virtualize mode the items have to be rendered from the (registered) Items collection, so the - options only register themselves here without rendering their items in place. *@ + @* In virtualize mode the items have to be rendered from the (registered) Items collection, and while + loading the callout shows the loading content instead of them, so the options only register + themselves here without rendering their items in place. Keeping them mounted (rather than dropping + them from the tree) preserves both the registration and the markup order of the items. *@ @@ -28,7 +66,7 @@ style="@StyleBuilder.Value" class="@ClassBuilder.Value" dir="@Dir?.ToString().ToLower()" - aria-owns="@(IsOpen? _calloutId : null)"> + aria-owns="@(IsOpen? _scrollContainerId : null)"> @if (LabelTemplate is not null) { } -
+ aria-controls="@(IsOpen? _scrollContainerId : null)"> @if (PrefixTemplate is not null) { @@ -69,20 +111,37 @@ } + @* No live region here: this element names the combobox through aria-labelledby, so a screen + reader reads the new selection when the focus returns to the trigger. Announcing it on every + render would repeat the whole selection after each keystroke typed into the combo input. *@ + class="bit-drp-tcn @Classes?.TextContainer"> @if (Chips) { - @foreach (var item in _selectedItems) + @foreach (var item in _selectedItems.Take(GetDisplayedItemsCount())) { @GetText(item) - + @if (IsEnabled && ReadOnly is false) + { + @* A button so the chip can be removed with the keyboard and is announced as an action. *@ +