Skip to content

Apply BitDropdown improvements (#12741) - #12745

Open
msynk wants to merge 22 commits into
bitfoundation:developfrom
msynk:12741-blazorui-dropdown-improvements
Open

Apply BitDropdown improvements (#12741)#12745
msynk wants to merge 22 commits into
bitfoundation:developfrom
msynk:12741-blazorui-dropdown-improvements

Conversation

@msynk

@msynk msynk commented Jul 21, 2026

Copy link
Copy Markdown
Member

closes #12741

Summary by CodeRabbit

  • New Features
    • Added advanced search with configurable matching modes, highlighting, type-ahead, and virtualization-aware navigation.
    • Added customizable empty, no-results, and loading states, including templates and status announcements.
    • Added multi-select “Select all,” selection limits, chip overflow handling, and clear actions.
  • Accessibility & UX
    • Improved keyboard navigation, focus management, ARIA semantics, responsive behavior, sizing, and disabled-option handling.
  • Documentation
    • Expanded dropdown demos covering templates, localization, loading, virtualization, RTL, styling, and customization.
  • Bug Fixes
    • Fixed chip removal interaction coverage and preserved selections when loading completes.

@msynk
msynk requested review from mhrastegari and yasmoradi July 21, 2026 14:51
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 606c2dd6-8f23-4a99-b7e9-8f71ea3ec1ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

BitDropdown adds configurable search, selection, loading, empty-state, accessibility, keyboard, virtualization, styling, public API, test, and demo behavior.

Changes

BitDropdown improvements

Layer / File(s) Summary
Rendering, search, and selection
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor, BitDropdown.razor.cs, _BitDropdownItem.razor
Adds shared empty/loading content, search modes, highlighting, selected-item hiding, select-all, selection limits, provider totals, overflow formatting, dynamic-item preservation, and updated option ARIA state.
Keyboard and focus integration
src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts, src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs, src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
Adds trigger and callout keyboard handling, printable type-ahead, virtualized option focus, ComboBox focus restoration, cancellation-safe navigation, and JavaScript lifecycle disposal.
Accessibility, contracts, and styling
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss, BitDropdownClassStyles.cs, BitDropdownSearchMode.cs, BitDropdownOption.cs
Adds search-mode contracts, cache-aware option updates, size variables, loading and empty-state styles, sticky headers, logical layout properties, visual states, and styling hooks.
Demo coverage and validation
src/BlazorUI/Demo/Client/.../Dropdown/*, src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/*
Expands metadata and examples for search, selection, accessibility, loading, virtualization, icons, sizing, localization, RTL, and close behavior. Tests cover callbacks, keyboard interaction, ARIA attributes, filtering, dynamic items, debounce, loading persistence, and selection limits.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: yasmoradi, mhrastegari

Poem

A rabbit checks each dropdown row,
Where search and loading states now show.
Keys guide focus through the list,
Chips have buttons hard to miss.
Empty results rest with care—
“Hop-hop!” says Bun, “focus is there!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main BitDropdown improvement work and references issue #12741.
Linked Issues check ✅ Passed The changes implement BitDropdown features and expand demo examples and descriptions required by [#12741].
Out of Scope Changes check ✅ Passed The changes remain focused on BitDropdown functionality, demos, styling, accessibility, and tests required by [#12741].
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@msynk

msynk commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

@msynk: I’ll perform a complete re-review of all changes in this PR.

✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 8 minutes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts (1)

183-185: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Page step is a hard-coded 10 items.

Extract it as a named constant next to VIRTUALIZE_RENDER_FRAMES, or derive it from the visible window (clientHeight / itemHeight) so PageUp/PageDown match what the user actually sees.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts` around lines 183 - 185,
Replace the hard-coded 10-item page step in the nextPage and prevPage branches
with a named constant declared alongside VIRTUALIZE_RENDER_FRAMES, or calculate
the step from the visible window using clientHeight and itemHeight. Reuse that
step for both navigation directions while preserving the existing boundary
clamping behavior.
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor (1)

311-339: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Select-all button stays focusable/clickable when the dropdown is disabled or read-only.

The bit-drp-ids class is applied for IsEnabled is false, but the <button> itself has no disabled attribute, so it remains tab-reachable and is also collected by _getItems in Dropdowns.ts. ReadOnly isn't reflected at all. The click handler bails out, so this is presentation/keyboard-focus only.

♻️ Proposed change
             <button `@onclick`="HandleOnSelectAllClick"
                     type="button"
                     role="checkbox"
+                    disabled="@(IsEnabled is false || ReadOnly)"
+                    aria-disabled="@(IsEnabled is false || ReadOnly)"
                     style="`@Styles`?.SelectAllButton"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`
around lines 311 - 339, Update the select-all button rendered in the
MultiSelect/ShowSelectAll block to be non-focusable and non-clickable when the
dropdown is disabled or read-only. Reflect both IsEnabled and ReadOnly on the
button’s disabled state so _getItems excludes it, while preserving its current
enabled behavior and styling.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor (1)

707-707: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider PreventRenderForMcpClient on the Virtualization example for consistency.

The equivalent Virtualization example in _BitDropdownItemDemo.razor (line 685) sets PreventRenderForMcpClient, while this one renders two 10k-item collections plus four ItemsProvider-backed dropdowns.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`
at line 707, Add PreventRenderForMcpClient to the Virtualization DemoExample
identified by Id "example20" and title "Virtualization", matching the equivalent
configuration in _BitDropdownItemDemo.razor.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`:
- Around line 341-346: Update the listbox markup in BitDropdown to conditionally
emit aria-labelledby using GetDropdownAriaLabelledby(), matching the trigger
behavior. Ensure no aria-labelledby attribute is rendered when neither
LabelTemplate nor Label creates the referenced label element.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 1448-1453: Update the callout keydown handling used by
HandleOnCalloutKeyDown and its Dropdowns.ts listener to prevent Tab’s default
browser focus movement, then close the callout and deliberately focus the
appropriate next or previous tabbable element based on Shift+Tab. Preserve
reachability of header/footer template controls and the search box in forward
tab order, rather than always refocusing _dropdownWrapperRef.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`:
- Around line 1742-1756: Update the sample Product class used by
example22CsharpCode and the corresponding class in the additional sample so it
declares the CssClass and CssStyle properties referenced by the nameSelectors
configuration; keep the existing selectors unchanged and ensure the copied
examples compile.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`:
- Around line 311-339: Update the select-all button rendered in the
MultiSelect/ShowSelectAll block to be non-focusable and non-clickable when the
dropdown is disabled or read-only. Reflect both IsEnabled and ReadOnly on the
button’s disabled state so _getItems excludes it, while preserving its current
enabled behavior and styling.

In `@src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts`:
- Around line 183-185: Replace the hard-coded 10-item page step in the nextPage
and prevPage branches with a named constant declared alongside
VIRTUALIZE_RENDER_FRAMES, or calculate the step from the visible window using
clientHeight and itemHeight. Reuse that step for both navigation directions
while preserving the existing boundary clamping behavior.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`:
- Line 707: Add PreventRenderForMcpClient to the Virtualization DemoExample
identified by Id "example20" and title "Virtualization", matching the equivalent
configuration in _BitDropdownItemDemo.razor.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 669d003b-b8c4-424c-b3d5-d5e8679f3ba6

📥 Commits

Reviewing files that changed from the base of the PR and between f1b4232 and f142ad3.

📒 Files selected for processing (19)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs

@msynk

msynk commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

@msynk: Starting a complete re-review of all changes in this PR.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs (1)

561-582: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Several new C# samples omit members their Razor sample references.

example9RazorCode uses comboBoxCustoms and comboBoxNameSelectors (lines 554-559), but example9CsharpCode defines neither, nor the Product class. Same gap in example16CsharpCode (razor uses nameSelectors, comboBoxCustoms, comboBoxNameSelectors), example22CsharpCode (razor uses nameSelectors) and example26CsharpCode (no Product). Sibling samples (example18, example19, example21) include the full boilerplate — worth aligning so the snippets are copy-pasteable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`
around lines 561 - 582, Complete the C# snippets in example9CsharpCode,
example16CsharpCode, example22CsharpCode, and example26CsharpCode with every
Product, collection, and selector member referenced by their corresponding Razor
snippets, including comboBoxCustoms, comboBoxNameSelectors, nameSelectors, and
Product as applicable. Align their declarations with the complete boilerplate
used by example18, example19, and example21 so each sample is independently
copy-pasteable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 860-883: Add a _positionsSelectionVersion backing field alongside
the existing position-cache fields, and include _selectionVersion in the cache
invalidation condition and cache-key updates within GetItemPositions(). This
must rebuild positions after selection changes, especially when
HideSelectedItems is enabled, while preserving the existing SearchText and
_optionsVersion cache behavior.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss`:
- Around line 1002-1008: Update the small dropdown styles in .bit-drp-sm so the
.bit-drp-pre/.bit-drp-suf height uses var(--bit-drp-h) instead of the fixed
spacing(3.75) value, allowing adorned controls to retain the configured small
height.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs`:
- Around line 841-847: Update the example16 sample’s backing declarations to
include the comboBoxItems list required by its BitDropdown Items binding,
matching the existing declaration pattern used in examples 9, 10, 14, 15, and
17. Ensure both the primary block and the additionally referenced range compile
without changing the sample’s other behavior.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs`:
- Around line 1401-1454: Update the example22 C# sample code associated with
example22RazorCode to declare and initialize the basicItems collection before it
is used by the Razor loops and LoadDelayedItems. Keep the existing
isLoadingItems and delayedItems declarations unchanged so the sample remains
self-contained.
- Around line 1102-1112: Update the example16 sample code, including the related
example16CsharpCode block, to declare and initialize the comboBoxItems list
before the BitDropdown markup iterates it. Match the existing comboBoxItems
declaration pattern used by examples 14, 15, and 17 while preserving the
existing basicItems declaration and AutoClearSearch sample behavior.

---

Nitpick comments:
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`:
- Around line 561-582: Complete the C# snippets in example9CsharpCode,
example16CsharpCode, example22CsharpCode, and example26CsharpCode with every
Product, collection, and selector member referenced by their corresponding Razor
snippets, including comboBoxCustoms, comboBoxNameSelectors, nameSelectors, and
Product as applicable. Align their declarations with the complete boilerplate
used by example18, example19, and example21 so each sample is independently
copy-pasteable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b79a8b8a-4de8-432f-a479-7002c7295fb6

📥 Commits

Reviewing files that changed from the base of the PR and between f1b4232 and fc59be3.

📒 Files selected for processing (21)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs

@msynk

msynk commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

@msynk: Starting a complete re-review of all changes in this PR.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs (1)

20-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Equals as a member name hides object.Equals on the type.

BitDropdownSearchMode.Equals(a, b) no longer resolves to the static object.Equals overload, and the name reads oddly in an enum of match modes. Renaming later would be a breaking public API change, so consider ExactMatch (or Exact) now.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs`
around lines 20 - 23, Rename the BitDropdownSearchMode enum member Equals to a
non-conflicting match-mode name such as ExactMatch, and update all references to
the member accordingly. Preserve the existing exact text matching behavior while
avoiding shadowing object.Equals and establishing the corrected public API name
now.
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs (1)

1744-1750: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Fire-and-forget ClearComboBoxInput now reaches Virtualize.RefreshDataAsync.

ClearComboBoxInput awaits SearchVirtualized(), so this discarded task performs JS/render work outside the caller's flow; any exception (e.g. an ObjectDisposedException when the component is torn down while the callout closes) is unobservable. Consider awaiting these from the caller of OnSetIsOpen or at least logging the faulted task.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`
around lines 1744 - 1750, Update the OnSetIsOpen flow to await
ClearComboBoxInput instead of discarding its task, allowing the
SearchVirtualized and Virtualize.RefreshDataAsync work and exceptions to remain
in the caller’s async flow. Preserve the existing ordering so the combo input is
cleared before invoking OnOpen or OnClose.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs (1)

626-628: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Combo sample TextSetter lambdas declare a nullable first parameter. BitDropdownNameSelectors.TextSetter is Action<string, TItem>? and the real code-behind uses (string text, Product item); the samples all use string?, so copied code warns on nullability.

  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs#L626-L628: change (string? text, Product item) to (string text, Product item) in example9CsharpCode.
  • .../_BitDropdownCustomDemo.razor.samples.cs#L1153-L1155: same change in example14CsharpCode.
  • .../_BitDropdownCustomDemo.razor.samples.cs#L1222-L1224: same change in example15CsharpCode.
  • .../_BitDropdownCustomDemo.razor.samples.cs#L1342-L1344: same change in example16CsharpCode.
  • .../_BitDropdownCustomDemo.razor.samples.cs#L1431-L1433: same change in example17CsharpCode.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`
around lines 626 - 628, Update the TextSetter lambda parameter type from
nullable string? to non-nullable string in example9CsharpCode at
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs:626-628,
and apply the same change in example14CsharpCode at :1153-1155,
example15CsharpCode at :1222-1224, example16CsharpCode at :1342-1344, and
example17CsharpCode at :1431-1433. Keep the Product item parameter and setter
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`:
- Around line 466-473: Keep the live-region container associated with
GetSearchResultsText permanently mounted in the dropdown markup, and
conditionally vary or clear only its text based on HasSearchText and IsLoading.
Preserve the existing polite, atomic status semantics while ensuring the element
remains in the accessibility tree before search-result announcements occur.

In `@src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts`:
- Around line 116-122: Update the visibility filter in BitDropdowns._getItems to
remove the offsetParent check, which excludes valid position-fixed dropdown
items. Replace it with a robust visibility check using checkVisibility() or
nonzero getBoundingClientRect() dimensions while preserving the existing
disabled and excluded-container filters.
- Around line 85-170: Serialize virtualized focus operations per callout by
adding a generation token associated with each callout and incrementing it at
the start of focusItem. Capture the token before awaiting _scrollFor, then abort
the stale invocation if the token changes after the await, preventing outdated
calls from applying interleaved items, scrolling, or focus results.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs`:
- Around line 488-512: Update the example9 sample declarations to include the
comboBoxItems collection referenced by the “Highlight in the ComboBox” markup,
matching the equivalent declarations in _BitDropdownItemDemo.razor.samples.cs
while retaining basicItems for the existing dropdown examples.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 1744-1750: Update the OnSetIsOpen flow to await ClearComboBoxInput
instead of discarding its task, allowing the SearchVirtualized and
Virtualize.RefreshDataAsync work and exceptions to remain in the caller’s async
flow. Preserve the existing ordering so the combo input is cleared before
invoking OnOpen or OnClose.

In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs`:
- Around line 20-23: Rename the BitDropdownSearchMode enum member Equals to a
non-conflicting match-mode name such as ExactMatch, and update all references to
the member accordingly. Preserve the existing exact text matching behavior while
avoiding shadowing object.Equals and establishing the corrected public API name
now.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`:
- Around line 626-628: Update the TextSetter lambda parameter type from nullable
string? to non-nullable string in example9CsharpCode at
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs:626-628,
and apply the same change in example14CsharpCode at :1153-1155,
example15CsharpCode at :1222-1224, example16CsharpCode at :1342-1344, and
example17CsharpCode at :1431-1433. Keep the Product item parameter and setter
behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 91a1b8ab-ff01-4c43-b4d6-289c5d006623

📥 Commits

Reviewing files that changed from the base of the PR and between f1b4232 and 8e3de5c.

📒 Files selected for processing (21)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs

Comment thread src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor Outdated
Comment thread src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts Outdated
Comment thread src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
@msynk

msynk commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

@msynk: Starting a complete re-review of all changes in this PR.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs (1)

659-702: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

example10CsharpCode is missing comboBoxNameSelectors.

The razor snippet (line 658) binds NameSelectors="comboBoxNameSelectors", but the C# sample only declares nameSelectors, plus no Product class is defined here either. Copying this example won't compile. Other combo samples (e.g. example9CsharpCode) declare both.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`
around lines 659 - 702, Update the example10CsharpCode sample to declare
comboBoxNameSelectors alongside nameSelectors, matching the NameSelectors
binding in the razor snippet and the pattern used by example9CsharpCode. Ensure
the sample also includes the Product model declaration required by these
selector definitions so the copied example compiles.
🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs (1)

844-856: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

IsMaxSelectedItemsReached reads Values, which can lag _selectedItems in unbound scenarios.

AddOrRemoveSelectedItem assigns through AssignValues, so Values is normally in sync, but dynamically added combo items are pushed straight into _selectedItems. Consider deriving the count from _selectedItems for consistency with the chips/summary counters (GetDisplayedItemsCount).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`
around lines 844 - 856, Update IsMaxSelectedItemsReached and its
IsValuesCountAtLeast usage to derive the selected-item count from _selectedItems
rather than Values, matching GetDisplayedItemsCount and keeping the limit check
consistent for dynamically added combo items.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor (1)

1012-1022: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Multi-select without any Values/DefaultValues binding, unlike the sibling examples.

Every other new multi-select sample here sets DefaultValues (e.g. HideSelectedItems at Line 1029, Item check icon at Line 1534), and the item-demo counterpart uses DefaultValues="@(Array.Empty<string>())" for this same AutoClearSearch example. Line 1506 (Chips remove icon (external)) has the same gap. Worth aligning so the demos start from a defined selection state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor`
around lines 1012 - 1022, Update the AutoClearSearch BitDropdown sample to bind
DefaultValues to an empty string array, matching the item-demo counterpart and
sibling multi-select examples. Also apply the same explicit empty DefaultValues
binding to the “Chips remove icon (external)” sample, while preserving their
existing selection behavior.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs (1)

1042-1047: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Empty/no-results/loading sample templates reference an undefined custom-drp-empty class. The new templates reuse class="custom-drp custom-drp-empty", but the only embedded <style> block in either samples file (example12) defines .custom-drp plus -lbl/-txt/-ph/-item/-header — never -empty. Copied as-is, the snippets render unstyled.

  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs#L1042-L1047: add a small <style> block defining .custom-drp-empty to example21RazorCode (and reuse it in example22RazorCode at Line 1114), or drop the class.
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs#L1362-L1367: apply the same fix to example21RazorCode and example22RazorCode (Line 1458).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs`
around lines 1042 - 1047, Define styling for the custom-drp-empty class, or
remove that class, so the empty/no-results/loading templates render correctly.
In
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs:1042-1047,
update example21RazorCode and reuse the fix in example22RazorCode around line
1114; apply the same change in _BitDropdownOptionDemo.razor.samples.cs:1362-1367
for example21RazorCode and around line 1458 for example22RazorCode.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 2110-2131: Invalidate the searched and display caches whenever the
ItemsProvider replaces _lastShownItems in the provider request flow. Update the
state after assigning providerResult.Items so _searchedItems, _displayItems, and
_itemPositions cannot be reused for the previous window, while preserving the
existing StateHasChanged and result-return behavior.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`:
- Around line 301-303: Update the dropdown search-mode prose to use the valid
BitDropdownSearchMode member ExactMatch instead of Equals in
_BitDropdownCustomDemo.razor lines 301-303 and _BitDropdownItemDemo.razor lines
299-301; leave the remaining mode descriptions unchanged.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`:
- Around line 428-433: Update the OnDynamicAdd entry in the component reference
table to use EventCallback<TItem> instead of EventCallback<string>, matching
BitDropdown’s declaration and the Product callback usage in the demos.

---

Outside diff comments:
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`:
- Around line 659-702: Update the example10CsharpCode sample to declare
comboBoxNameSelectors alongside nameSelectors, matching the NameSelectors
binding in the razor snippet and the pattern used by example9CsharpCode. Ensure
the sample also includes the Product model declaration required by these
selector definitions so the copied example compiles.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 844-856: Update IsMaxSelectedItemsReached and its
IsValuesCountAtLeast usage to derive the selected-item count from _selectedItems
rather than Values, matching GetDisplayedItemsCount and keeping the limit check
consistent for dynamically added combo items.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs`:
- Around line 1042-1047: Define styling for the custom-drp-empty class, or
remove that class, so the empty/no-results/loading templates render correctly.
In
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs:1042-1047,
update example21RazorCode and reuse the fix in example22RazorCode around line
1114; apply the same change in _BitDropdownOptionDemo.razor.samples.cs:1362-1367
for example21RazorCode and around line 1458 for example22RazorCode.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor`:
- Around line 1012-1022: Update the AutoClearSearch BitDropdown sample to bind
DefaultValues to an empty string array, matching the item-demo counterpart and
sibling multi-select examples. Also apply the same explicit empty DefaultValues
binding to the “Chips remove icon (external)” sample, while preserving their
existing selection behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a25ae613-18cf-495e-a6cb-07aa77252c6f

📥 Commits

Reviewing files that changed from the base of the PR and between 826c1ad and 3ee561f.

📒 Files selected for processing (21)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs

@msynk

msynk commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

@msynk: Starting a complete re-review of all changes in this PR.

✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 11 seconds.

@msynk

msynk commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

@msynk I will perform a complete re-review of all changes in this pull request.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor (1)

53-62: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep options registered when IsLoading changes.

When IsLoading falls to false while Virtualize is false, the option markup is moved from the hidden wrapper to the normal dropdown wrapper. BitDropdownOption registers in OnInitializedAsync and unregisters from Dispose, so moving the options creates new component instances while the old instances are disposed. If disposal runs after the new instances register, the dropdown removes the items from Items and _selectedItems, leaving an empty callout selection until the next parameter set. Add a test that starts with IsLoading true, the options selected, and then flips IsLoading to false.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`
around lines 53 - 62, The conditional rendering in BitDropdown must keep the
same option component instances mounted when IsLoading changes, including when
Virtualize is false, instead of moving Options or ChildContent between the
hidden and normal wrappers. Adjust the BitDropdown render structure so options
remain registered throughout loading transitions, and add a regression test
covering an initially loading dropdown with selected options that then sets
IsLoading to false while preserving the selection.
🧹 Nitpick comments (4)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor (1)

88-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two multi-select examples set DefaultValue instead of DefaultValues.

DefaultValue is the single-select initializer, and DefaultValues is the multi-select one. Both dropdowns declare MultiSelect, so the value passed to DefaultValue has no effect on the initial selection. Both examples are copied into user projects, so they teach the wrong parameter for the mode.

If the parameter is only present so that Razor can infer TValue, use DefaultValues for that purpose instead. It infers the same type and matches the mode.

♻️ Proposed refactor
         <BitDropdown Label="StickyHeaders"
                      StickyHeaders
                      MultiSelect
                      Items="GetGroupedCustoms()"
                      NameSelectors="nameSelectors"
-                     DefaultValue="`@string.Empty`"
+                     DefaultValues="@(Array.Empty<string>())"
                      Placeholder="Select items" />
         <BitDropdown MultiSelect
                      ShowSelectAll
                      ShowSearchBox
                      SelectAllText="Select all of them"
                      Items="GetBasicCustoms()"
                      NameSelectors="nameSelectors"
                      Placeholder="Select items"
-                     DefaultValue="`@string.Empty`"
+                     DefaultValues="@(Array.Empty<string>())"
                      SearchBoxPlaceholder="Search items"
                      Label="Custom text & search" />

Also applies to: 993-1002

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`
around lines 88 - 94, Update both multi-select dropdown examples in
_BitDropdownCustomDemo, including the StickyHeaders example and the additional
occurrence, to use DefaultValues instead of DefaultValue. Preserve the existing
empty-string initializer so Razor type inference remains intact while matching
the MultiSelect parameter.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs (1)

1814-1871: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The Type column of componentPublicMembers now mixes bare types and full signatures.

The new entries give complete signatures, for example Task SelectItem(TItem? item) and ValueTask FocusAsync(bool preventScroll = false). The neighboring entries FocusComboInputAsync (Line 1857) and FocusSearchInputAsync (Line 1869) still give only ValueTask. The reference table then presents two formats for the same kind of member. Use one format for every method entry.

♻️ Proposed refactor
         new()
         {
             Name = "FocusComboInputAsync",
-            Type = "ValueTask",
+            Type = "ValueTask FocusComboInputAsync(bool preventScroll = false)",
             Description = "Gives focus to the combo input element.",
         },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`
around lines 1814 - 1871, Update the Type values for the method entries
FocusComboInputAsync and FocusSearchInputAsync in componentPublicMembers to use
complete method signatures, matching SelectItem, UnselectItem,
RefreshItemsAsync, AssignIsOpen, and FocusAsync. Keep property entries such as
ComboInputElement and SearchInputElement as bare types.
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss (1)

1020-1038: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The size modifiers depend on source order to beat the base declarations.

.bit-drp (Line 23) and .bit-drp-cal (Line 691) both include drp-size-medium, and the size modifiers have the same specificity (one class). The override works only because .bit-drp-sm and .bit-drp-lg appear later in the file. A future re-order of this stylesheet, or a build step that groups rules, silently restores the medium values. Bind the modifiers to the element they modify to make the override specificity-based instead of order-based.

.bit-drp-md is then also redundant, because the base rule already supplies the medium values.

♻️ Proposed refactor
-.bit-drp-sm {
+.bit-drp.bit-drp-sm,
+.bit-drp-cal.bit-drp-sm {
     --bit-drp-fs: #{spacing(1.5)};
     --bit-drp-h: #{spacing(3.25)};
     --bit-drp-lh: #{spacing(3)};
     --bit-drp-itm-h: #{spacing(3.75)};
     --bit-drp-itm-fs: #{spacing(1.625)};
 }
 
-.bit-drp-md {
-    `@include` drp-size-medium;
-}
-
-.bit-drp-lg {
+.bit-drp.bit-drp-lg,
+.bit-drp-cal.bit-drp-lg {
     --bit-drp-fs: #{spacing(2)};
     --bit-drp-h: #{spacing(5)};
     --bit-drp-lh: #{spacing(4.75)};
     --bit-drp-itm-h: #{spacing(5.5)};
     --bit-drp-itm-fs: #{spacing(2.125)};
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss` around
lines 1020 - 1038, Update the dropdown size modifiers `.bit-drp-sm` and
`.bit-drp-lg` so their selectors are bound to the `.bit-drp` or `.bit-drp-cal`
element they modify, giving them higher specificity than the `drp-size-medium`
declarations. Remove the redundant `.bit-drp-md` rule because the base medium
sizing already provides those values.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs (1)

2275-2310: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Declare the Product class in example26CsharpCode.

The nameSelectors initializer in this sample reads c.Label, c.Key, c.Payload, c.Disabled, c.Visible, c.Type, c.Text, c.Title and c.Value, but the sample never declares Product. A reader who copies this snippet cannot compile it. Every other sample in this file that uses the full selector set declares the class inline (for example lines 57-68).

The same gap exists in example7CsharpCode (lines 407-428).

📝 Proposed fix
     private readonly string example26CsharpCode = @"
+public class Product
+{
+    public string? Label { get; set; }
+    public string? Key { get; set; }
+    public object? Payload { get; set; }
+    public bool Disabled { get; set; }
+    public bool Visible { get; set; } = true;
+    public BitDropdownItemType Type { get; set; } = BitDropdownItemType.Normal;
+    public string? Text { get; set; }
+    public string? Title { get; set; }
+    public string? Value { get; set; }
+}
+
 private List<Product> comboBoxCustoms = new()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`
around lines 2275 - 2310, Declare the Product class inline within both
example26CsharpCode and example7CsharpCode, including the properties required by
their BitDropdownNameSelectors initializers: Label, Key, Payload, Disabled,
Visible, Type, Text, Title, and Value. Match the inline Product declaration
pattern used by the other samples in the file so each copied snippet compiles
independently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 2963-2976: Gate the AutoSelectFirstMatch branch in the surrounding
selection method on an active search term, such as non-null, non-empty
SearchText, before calling GetDisplayItems(). Preserve the existing match
filtering and AddOrRemoveSelectedItem behavior once a search is active, and
avoid selecting any item while the typed text is shorter than MinSearchLength.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`:
- Around line 69-79: Update the screen-reader announcement in the Grouping prose
of the dropdown demo to match the rendered GetGroupedCustoms() data, using
Broccoli’s seventh-of-eighteen position, or remove the specific position and
count while preserving the grouping explanation.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs`:
- Around line 110-139: Update the first “Grouped options” BitDropdown in
example2RazorCode to render its options by iterating groupedItems, matching the
rendered demo and the existing StickyHeaders dropdown below it. Remove the
shortened inline option list while preserving the dropdown’s current properties
and option mapping.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`:
- Around line 252-263: Update the Type declaration for the FindItemFunction
entry to use a nullable TItem return value: Func<ICollection<TItem>, string,
TItem?>?. Keep the surrounding description and ExistsSelectedItemFunction entry
unchanged.

---

Outside diff comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`:
- Around line 53-62: The conditional rendering in BitDropdown must keep the same
option component instances mounted when IsLoading changes, including when
Virtualize is false, instead of moving Options or ChildContent between the
hidden and normal wrappers. Adjust the BitDropdown render structure so options
remain registered throughout loading transitions, and add a regression test
covering an initially loading dropdown with selected options that then sets
IsLoading to false while preserving the selection.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss`:
- Around line 1020-1038: Update the dropdown size modifiers `.bit-drp-sm` and
`.bit-drp-lg` so their selectors are bound to the `.bit-drp` or `.bit-drp-cal`
element they modify, giving them higher specificity than the `drp-size-medium`
declarations. Remove the redundant `.bit-drp-md` rule because the base medium
sizing already provides those values.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`:
- Around line 88-94: Update both multi-select dropdown examples in
_BitDropdownCustomDemo, including the StickyHeaders example and the additional
occurrence, to use DefaultValues instead of DefaultValue. Preserve the existing
empty-string initializer so Razor type inference remains intact while matching
the MultiSelect parameter.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`:
- Around line 2275-2310: Declare the Product class inline within both
example26CsharpCode and example7CsharpCode, including the properties required by
their BitDropdownNameSelectors initializers: Label, Key, Payload, Disabled,
Visible, Type, Text, Title, and Value. Match the inline Product declaration
pattern used by the other samples in the file so each copied snippet compiles
independently.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`:
- Around line 1814-1871: Update the Type values for the method entries
FocusComboInputAsync and FocusSearchInputAsync in componentPublicMembers to use
complete method signatures, matching SelectItem, UnselectItem,
RefreshItemsAsync, AssignIsOpen, and FocusAsync. Keep property entries such as
ComboInputElement and SearchInputElement as bare types.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0990fc2d-1828-4dea-ae47-8f7e1b143c04

📥 Commits

Reviewing files that changed from the base of the PR and between 3685dde and 5c4aae5.

📒 Files selected for processing (22)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs

Comment thread src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs Outdated
@msynk

msynk commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

@msynk I will perform a complete re-review of all changes in this pull request.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (9)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs (2)

2355-2400: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Diacritic folding runs per item on every match and highlight.

IsItemTextMatch and GetHighlightIndex call RemoveDiacritics for each item text. With SearchIgnoreDiacritics and HighlightSearch both enabled, each item text is folded twice per search pass, and each fold allocates a StringBuilder plus a normalized string per character. Cache the folded item text (for example in a Dictionary<string, string> reset with _optionsVersion) to keep long lists responsive.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`
around lines 2355 - 2400, Cache diacritic-folded item text in the dropdown,
keyed by the original text, and clear that cache when the options/search version
changes (for example via _optionsVersion). Update IsItemTextMatch and
GetHighlightIndex to reuse the cached folded value when SearchIgnoreDiacritics
is enabled, while preserving existing matching and highlighting behavior.

2624-2639: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

GetSelectAllCandidateItems allocates a new list on every render.

GetSelectAllState runs during each callout render and materializes the full candidate list. For long item collections this repeats the filter on every keystroke. Consider counting without materializing, or caching the candidates with the existing search/options/selection versions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`
around lines 2624 - 2639, Update GetSelectAllState and
GetSelectAllCandidateItems to avoid materializing a new candidate list on every
render; count matching normal, visible, enabled items directly while preserving
the existing empty, all-selected, and any-selected results. If caching is
preferred, invalidate it whenever the searched items or relevant dropdown
options/selection state changes.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs (2)

252-263: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the missing DefaultValue to the two new delegate entries.

Every other nullable parameter in this table sets DefaultValue = "null", including SearchFunction and DynamicValueGenerator. ExistsSelectedItemFunction and FindItemFunction omit it, so the rendered reference table shows an empty default cell for these two rows only.

♻️ Proposed fix
             Name = "ExistsSelectedItemFunction",
             Type = "Func<ICollection<TItem>, string, bool>?",
+            DefaultValue = "null",
             Description = "Decides whether the text committed in the ComboBox mode already stands for one of the selected items, in place of the default comparison of that text with the item texts, ignoring case. It receives the selected items and the committed text, and returning true stops the commit, so the same item cannot be selected (or created) twice under a name your data considers equivalent.",
         },
         new()
         {
             Name = "FindItemFunction",
             Type = "Func<ICollection<TItem>, string, TItem?>?",
+            DefaultValue = "null",
             Description = "Finds the item the text committed in the ComboBox mode stands for, in place of the default comparison of that text with the item texts, ignoring case. It receives the items and the committed text; the item it returns gets selected, and only when it returns none does AutoSelectFirstMatch and then Dynamic get their turn.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`
around lines 252 - 263, Add DefaultValue = "null" to the
ExistsSelectedItemFunction and FindItemFunction delegate entries, matching the
existing nullable parameter metadata such as SearchFunction and
DynamicValueGenerator.

30-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Restore the alphabetical order of the parameter table.

The table is otherwise alphabetical, which is how a reader locates a parameter. HideSelectedItems and HighlightSearch now sit between AutoSelectFirstMatch and CalloutFooterTemplate, and ClearButtonAriaLabel sits after Color. Move HideSelectedItems and HighlightSearch next to HeaderTemplate, and move ClearButtonAriaLabel before Color.

Also applies to: 144-150

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`
around lines 30 - 50, Restore alphabetical ordering in the parameter table: move
the HideSelectedItems and HighlightSearch entries to immediately follow
HeaderTemplate, and move ClearButtonAriaLabel to immediately precede Color. Keep
each entry’s existing definition unchanged.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs (1)

1049-1060: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the indentation inside the GetDataCustoms sample.

The first list element is indented by four spaces and the remaining eight elements by eight spaces. This string is displayed to the reader as the copyable sample, so the misalignment is visible.

♻️ Proposed fix
 private List<Product> GetDataCustoms() => new()
 {
     new() { Type = BitDropdownItemType.Header, Text = ""Items"", Payload = new DropdownItemData { IconName = ""BulletedList2"" } },
-        new() { Text = ""Item a"", Value = ""A"", Payload = new DropdownItemData { IconName = ""Memo"" } },
-        new() { Text = ""Item b"", Value = ""B"", Payload = new DropdownItemData { IconName = ""Print"" } },
-        new() { Text = ""Item c"", Value = ""C"", Payload = new DropdownItemData { IconName = ""ShoppingCart"" } },
-        new() { Type = BitDropdownItemType.Divider },
-        new() { Type = BitDropdownItemType.Header, Text = ""More Items"", Payload = new DropdownItemData { IconName = ""BulletedTreeList"" } },
-        new() { Text = ""Item d"", Value = ""D"", Payload = new DropdownItemData { IconName = ""Train"" } },
-        new() { Text = ""Item e"", Value = ""E"", Payload = new DropdownItemData { IconName = ""Repair"" } },
-        new() { Text = ""Item f"", Value = ""F"", Payload = new DropdownItemData { IconName = ""Running"" } }
+    new() { Text = ""Item a"", Value = ""A"", Payload = new DropdownItemData { IconName = ""Memo"" } },
+    new() { Text = ""Item b"", Value = ""B"", Payload = new DropdownItemData { IconName = ""Print"" } },
+    new() { Text = ""Item c"", Value = ""C"", Payload = new DropdownItemData { IconName = ""ShoppingCart"" } },
+    new() { Type = BitDropdownItemType.Divider },
+    new() { Type = BitDropdownItemType.Header, Text = ""More Items"", Payload = new DropdownItemData { IconName = ""BulletedTreeList"" } },
+    new() { Text = ""Item d"", Value = ""D"", Payload = new DropdownItemData { IconName = ""Train"" } },
+    new() { Text = ""Item e"", Value = ""E"", Payload = new DropdownItemData { IconName = ""Repair"" } },
+    new() { Text = ""Item f"", Value = ""F"", Payload = new DropdownItemData { IconName = ""Running"" } }
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`
around lines 1049 - 1060, Align the indentation of every initializer inside the
GetDataCustoms list so all elements use the same indentation as the first
element, preserving the existing item content and ordering.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor (1)

10-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add Name to the generated parameter table.

BitDropdown inherits Name from BitInputBase, and it binds that value to the hidden native <select> with name="@name". Add Name to BitDropdownDemo.razor.cs so the reference matches the prose.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`
around lines 10 - 11, Add the inherited Name parameter to the generated
parameter table in BitDropdownDemo.razor.cs, alongside the existing BitDropdown
parameters, so it documents the Name value used by the hidden native select and
matches the prose in _BitDropdownCustomDemo.razor.
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTests.cs (1)

10-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Set the JSInterop mode to loose in this test.

Every other BitDropdown test that renders items and then re-renders sets Context.JSInterop.Mode = JSRuntimeMode.Loose; first. This test does not. BitDropdown calls into JS from its parameter and render hooks, so the second render at line 15 can reach a JS call. In the default strict mode bUnit throws JSRuntimeUnhandledInvocationException for any unplanned call, which makes this test fragile against unrelated changes in the component.

💚 Proposed fix
     public void BitDropdownShouldKeepTheSelectionWhenLoadingEnds()
     {
+        Context.JSInterop.Mode = JSRuntimeMode.Loose;
+
         var component = RenderComponent<BitDropdownLoadingTest>(parameters => parameters.Add(p => p.IsLoading, true));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTests.cs`
around lines 10 - 19, Set Context.JSInterop.Mode to JSRuntimeMode.Loose at the
start of BitDropdownShouldKeepTheSelectionWhenLoadingEnds, before rendering the
component, so parameter and render-hook JS calls remain unplanned during the
subsequent re-render.
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs (1)

2192-2233: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Good coverage of the diacritic folding, with one gap.

This test proves the highlighted range still lines up with the accented text for José and Müller. Both are precomposed single code points, so folding them keeps one character per character. It does not cover a text that is already decomposed (for example José written as e plus U+0301), where folding can change the character count and shift the highlight range. That is the exact case the highlighted guard in _BitDropdownItem.razor does not defend against.

Consider adding a decomposed item to GetAccentedDropdownItems to close the gap.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs`
around lines 2192 - 2233, Extend GetAccentedDropdownItems with an item
containing a decomposed accented character, such as a base letter followed by a
combining diacritic, and update
BitDropdownSearchIgnoreDiacriticsShouldMatchTheFoldedText to search for and
assert that item. Verify highlighted output remains correct when folding changes
the character count, covering the highlighted guard in _BitDropdownItem.razor.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor (1)

1509-1511: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The Virtualization example renders for MCP clients while every other example opts out.

Every other DemoExample in this file carries PreventRenderForMcpClient. This one does not. The body is only a text note, so the behavior is harmless, but the difference looks unintentional. Confirm the omission is deliberate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor`
around lines 1509 - 1511, Update the Virtualization DemoExample identified by
example24 to explicitly use the same PreventRenderForMcpClient setting as the
other examples in this file, unless the omission is intentionally required;
preserve its title, RazorCode, Id, and explanatory content.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor`:
- Around line 83-88: Update the StickyHeaders multi-select example and the
matching examples around the referenced locations to use
DefaultValues="@(Array.Empty<string>())" instead of
DefaultValue="`@string.Empty`". Preserve the existing MultiSelect configuration
and other dropdown parameters.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 2355-2400: Cache diacritic-folded item text in the dropdown, keyed
by the original text, and clear that cache when the options/search version
changes (for example via _optionsVersion). Update IsItemTextMatch and
GetHighlightIndex to reuse the cached folded value when SearchIgnoreDiacritics
is enabled, while preserving existing matching and highlighting behavior.
- Around line 2624-2639: Update GetSelectAllState and GetSelectAllCandidateItems
to avoid materializing a new candidate list on every render; count matching
normal, visible, enabled items directly while preserving the existing empty,
all-selected, and any-selected results. If caching is preferred, invalidate it
whenever the searched items or relevant dropdown options/selection state
changes.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`:
- Around line 10-11: Add the inherited Name parameter to the generated parameter
table in BitDropdownDemo.razor.cs, alongside the existing BitDropdown
parameters, so it documents the Name value used by the hidden native select and
matches the prose in _BitDropdownCustomDemo.razor.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs`:
- Around line 1049-1060: Align the indentation of every initializer inside the
GetDataCustoms list so all elements use the same indentation as the first
element, preserving the existing item content and ordering.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor`:
- Around line 1509-1511: Update the Virtualization DemoExample identified by
example24 to explicitly use the same PreventRenderForMcpClient setting as the
other examples in this file, unless the omission is intentionally required;
preserve its title, RazorCode, Id, and explanatory content.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`:
- Around line 252-263: Add DefaultValue = "null" to the
ExistsSelectedItemFunction and FindItemFunction delegate entries, matching the
existing nullable parameter metadata such as SearchFunction and
DynamicValueGenerator.
- Around line 30-50: Restore alphabetical ordering in the parameter table: move
the HideSelectedItems and HighlightSearch entries to immediately follow
HeaderTemplate, and move ClearButtonAriaLabel to immediately precede Color. Keep
each entry’s existing definition unchanged.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTests.cs`:
- Around line 10-19: Set Context.JSInterop.Mode to JSRuntimeMode.Loose at the
start of BitDropdownShouldKeepTheSelectionWhenLoadingEnds, before rendering the
component, so parameter and render-hook JS calls remain unplanned during the
subsequent re-render.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs`:
- Around line 2192-2233: Extend GetAccentedDropdownItems with an item containing
a decomposed accented character, such as a base letter followed by a combining
diacritic, and update BitDropdownSearchIgnoreDiacriticsShouldMatchTheFoldedText
to search for and assert that item. Verify highlighted output remains correct
when folding changes the character count, covering the highlighted guard in
_BitDropdownItem.razor.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 778d8b34-83b0-40d7-a81f-e48401077422

📥 Commits

Reviewing files that changed from the base of the PR and between 3685dde and d63e748.

📒 Files selected for processing (24)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs

@msynk

msynk commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

@msynk I will perform a complete re-review of all changes in this pull request.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss (1)

672-676: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Drive the clear button and the responsive add button from --bit-drp-h.

.bit-drp-clr and .bit-drp-cai keep a fixed spacing(3.75) height. .bit-drp-sm sets --bit-drp-h to spacing(3.25), so a small dropdown with ShowClearButton is forced taller than its configured size. A large dropdown (spacing(5)) leaves the button smaller than the control. The same root cause was reported earlier for .bit-drp-pre/.bit-drp-suf, which now use the variable.

🎨 Proposed fix
 .bit-drp-clr,
 .bit-drp-cai {
     display: flex;
-    width: spacing(3.75);
-    height: spacing(3.75);
+    width: var(--bit-drp-h);
+    height: var(--bit-drp-h);
     justify-content: center;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss` around
lines 672 - 676, Update the shared .bit-drp-clr and .bit-drp-cai styles to
derive their height from the dropdown’s --bit-drp-h custom property instead of
fixed spacing(3.75), matching the existing .bit-drp-pre and .bit-drp-suf
behavior while preserving their width and flex layout.
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs (1)

2093-2097: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Tab still runs its browser default before the callout closes.

Tab is not in CALLOUT_KEYS in Dropdowns.ts, so its default is not prevented. The browser moves the focus to the element that follows the callout in DOM order, and this handler then returns the focus to the trigger. The user-visible result is that Tab and Shift+Tab appear to do nothing.

Add Tab to the prevented keys in Dropdowns.ts and move the focus deliberately here, or leave the default in place and do not refocus the trigger on Tab.

This repeats an earlier review comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`
around lines 2093 - 2097, Add Tab to the prevented-key set CALLOUT_KEYS in
Dropdowns.ts so its browser default does not run, and retain the deliberate
focus restoration in CloseCalloutAndRestoreFocus for the "Tab" case of the
dropdown keyboard handler. Ensure Tab and Shift+Tab use the intended focus
movement rather than being restored to the trigger after native navigation.
🧹 Nitpick comments (5)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor (1)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shorten the PageOutlet description.

PageOutlet.Description feeds the page meta description. This value is a single sentence of roughly 800 characters. Search engines truncate meta descriptions near 160 characters, so most of the feature list is not shown. Keep a short summary here and leave the full detail in the DemoPage description on line 11.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor`
at line 6, Shorten the PageOutlet Description value to a concise summary
suitable for search-engine meta descriptions, targeting roughly 160 characters
or fewer. Preserve the full feature list in the DemoPage description and change
only the PageOutlet metadata text.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs (1)

391-402: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Keep the parameter table alphabetical.

The list is alphabetical elsewhere. MaxSelectedItems precedes MaxDisplayedItems at lines 391-402, and OverflowTextFormat precedes Options at lines 534-547. Swap the two pairs so readers can find the new parameters.

Also applies to: 534-540

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`
around lines 391 - 402, Reorder the parameter entries in the parameter table
alphabetically: move MaxDisplayedItems before MaxSelectedItems, and move Options
before OverflowTextFormat. Keep each entry’s existing metadata and description
unchanged.
src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss (1)

848-866: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify the spinner animation and consider reduced motion.

Line 858 sets the timing function to linear through the animation shorthand, and line 859 immediately overrides it. Declare the timing function once. The spinner also animates continuously; add a prefers-reduced-motion: reduce fallback if the design system supports one.

♻️ Proposed fix
-    animation: bit-drp-spinner-animation 1.3s linear infinite;
-    animation-timing-function: cubic-bezier(0.53, 0.21, 0.29, 0.67);
+    animation: bit-drp-spinner-animation 1.3s cubic-bezier(0.53, 0.21, 0.29, 0.67) infinite;
+
+    `@media` (prefers-reduced-motion: reduce) {
+        animation-duration: 3s;
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss` around
lines 848 - 866, Update the .bit-drp-spn animation declaration to define the
intended timing function only once instead of overriding the shorthand’s linear
value with animation-timing-function. Add the project’s supported
prefers-reduced-motion: reduce fallback for this spinner so continuous animation
is disabled or otherwise reduced while preserving normal behavior by default.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs (1)

900-912: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare DropdownItemData in the example13CsharpCode sample.

The Razor part of example 13 casts item.Data as DropdownItemData, and dataItems builds new DropdownItemData { ... }. The C# sample does not declare that class, so the snippet does not compile when copied. The matching sample in _BitDropdownItemDemo.razor.samples.cs declares it.

📝 Proposed fix
     private readonly string example13CsharpCode = @"
+public class DropdownItemData
+{
+    public string? IconName { get; set; }
+}
+
 private readonly List<BitDropdownItem<string>> dataItems =
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs`
around lines 900 - 912, Update the example13CsharpCode sample to declare the
DropdownItemData class used by its item.Data initializers and the Razor cast,
matching the corresponding declaration in the BitDropdownItem demo sample.
src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts (1)

196-205: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

The re-render detection compares element identity only.

Virtualize can reuse the same DOM nodes and change only their content. In that case rendered[0] !== first stays false for all 20 frames, so every PageUp/PageDown waits the full VIRTUALIZE_RENDER_FRAMES budget before the focus moves. On a 60 Hz display that is about 330 ms of latency per key press.

Compare a value that changes with the window, such as the first item's id or textContent, in addition to the identity check.

♻️ Proposed change
             const first = items[0];
             const last = items[items.length - 1];
+            const firstKey = first.id || first.textContent;
+            const lastKey = last.id || last.textContent;
 
             scroller.scrollTop = top;
 
             for (let i = 0; i < Dropdowns.VIRTUALIZE_RENDER_FRAMES; i++) {
                 await new Promise<void>(resolve => requestAnimationFrame(() => resolve()));
 
                 const rendered = Dropdowns._getItems(callout);
-                if (rendered.length > 0 && (rendered[0] !== first || rendered[rendered.length - 1] !== last)) {
+                const renderedFirst = rendered[0];
+                const renderedLast = rendered[rendered.length - 1];
+                if (rendered.length > 0 &&
+                    (renderedFirst !== first || renderedLast !== last ||
+                     (renderedFirst.id || renderedFirst.textContent) !== firstKey ||
+                     (renderedLast.id || renderedLast.textContent) !== lastKey)) {
                     return { items: rendered, mode: nextMode };
                 }
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts` around lines 196 - 205,
Update the re-render detection loop in the Dropdowns virtualization flow to
compare a window-dependent value, such as the first and last rendered items’ id
or textContent, alongside DOM element identity. Ensure reused nodes with changed
content cause immediate return, while preserving the existing frame polling and
fallback behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor`:
- Around line 437-446: Update the shared loadingContent and emptyContent
fragments used within the listbox scroll container to make their root elements
presentational, preserving the existing loading and empty-state content and
status announcement behavior. Do not alter option rendering or the listbox
container itself.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss`:
- Around line 163-167: Insert a blank line between the position: relative
declaration and the explanatory comment in the Dropdown styles, leaving the
align-items and min-height declarations unchanged.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor`:
- Around line 1420-1422: Rewrite the broken OpenOnFocus description sentence to
state that the component distinguishes user-initiated focus from focus caused by
its own focus management. Apply the same wording in _BitDropdownCustomDemo.razor
lines 1420-1422, _BitDropdownItemDemo.razor lines 1363-1365, and
_BitDropdownOptionDemo.razor lines 1743-1747.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTests.cs`:
- Around line 12-15: Configure bUnit JS interop as loose in
BitDropdownLoadingTests by setting Context.JSInterop.Mode to JSRuntimeMode.Loose
before the initial RenderComponent<BitDropdownLoadingTest> call. Keep the
existing IsLoading parameter render transitions unchanged.

---

Outside diff comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss`:
- Around line 672-676: Update the shared .bit-drp-clr and .bit-drp-cai styles to
derive their height from the dropdown’s --bit-drp-h custom property instead of
fixed spacing(3.75), matching the existing .bit-drp-pre and .bit-drp-suf
behavior while preserving their width and flex layout.

---

Duplicate comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs`:
- Around line 2093-2097: Add Tab to the prevented-key set CALLOUT_KEYS in
Dropdowns.ts so its browser default does not run, and retain the deliberate
focus restoration in CloseCalloutAndRestoreFocus for the "Tab" case of the
dropdown keyboard handler. Ensure Tab and Shift+Tab use the intended focus
movement rather than being restored to the trigger after native navigation.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss`:
- Around line 848-866: Update the .bit-drp-spn animation declaration to define
the intended timing function only once instead of overriding the shorthand’s
linear value with animation-timing-function. Add the project’s supported
prefers-reduced-motion: reduce fallback for this spinner so continuous animation
is disabled or otherwise reduced while preserving normal behavior by default.

In `@src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts`:
- Around line 196-205: Update the re-render detection loop in the Dropdowns
virtualization flow to compare a window-dependent value, such as the first and
last rendered items’ id or textContent, alongside DOM element identity. Ensure
reused nodes with changed content cause immediate return, while preserving the
existing frame polling and fallback behavior.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs`:
- Around line 900-912: Update the example13CsharpCode sample to declare the
DropdownItemData class used by its item.Data initializers and the Razor cast,
matching the corresponding declaration in the BitDropdownItem demo sample.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor`:
- Line 6: Shorten the PageOutlet Description value to a concise summary suitable
for search-engine meta descriptions, targeting roughly 160 characters or fewer.
Preserve the full feature list in the DemoPage description and change only the
PageOutlet metadata text.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs`:
- Around line 391-402: Reorder the parameter entries in the parameter table
alphabetically: move MaxDisplayedItems before MaxSelectedItems, and move Options
before OverflowTextFormat. Keep each entry’s existing metadata and description
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: abab0873-0cd2-4541-be01-d3f9e63dcfaf

📥 Commits

Reviewing files that changed from the base of the PR and between 679ac06 and fe9fc37.

📒 Files selected for processing (24)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdownSearchMode.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/_BitDropdownItem.razor
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DropdownsJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/Dropdowns.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/BitDropdownDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/Dropdown/_BitDropdownOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownLoadingTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/Dropdown/BitDropdownTests.cs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The BitDropdown improvements

1 participant