Skip to content

Apply BitChoiceGroup improvements (#12740) - #12743

Open
msynk wants to merge 13 commits into
bitfoundation:developfrom
msynk:12740-blazorui-choicegroup-improvements
Open

Apply BitChoiceGroup improvements (#12740)#12743
msynk wants to merge 13 commits into
bitfoundation:developfrom
msynk:12740-blazorui-choicegroup-improvements

Conversation

@msynk

@msynk msynk commented Jul 21, 2026

Copy link
Copy Markdown
Member

closes #12740

Summary by CodeRabbit

  • New Features

    • Added per-item/option Description, Suffix, and Title, plus DescriptionTemplate and ItemSuffixTemplate; introduced LabelPosition and Gap.
    • Added one-time AutoFocus and new callbacks OnFocus / OnBlur (replacing Reversed).
  • Accessibility Improvements

    • Expanded ARIA state/metadata and improved aria-describedby wiring for group vs item descriptions.
  • Styling

    • Updated choice-group layout, dot/radio indicator behavior, focus-ring styling, and read-only/disabled affordances.
  • Demos & Tests

    • Refreshed demos/metadata and significantly expanded accessibility, events, rendering, and state synchronization test coverage.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

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

BitChoiceGroup adds expanded ARIA output, descriptions, autofocus, configurable gaps, label positioning, suffix/title customization, synchronized selection state, updated styling, expanded demos, and comprehensive accessibility, interaction, content, options, state, and style tests.

Changes

ChoiceGroup component and rendering

Layer / File(s) Summary
Component contracts, state, and accessible rendering
src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/*
Adds description, autofocus, gap, label-position, suffix-template, focus-event, ARIA, selection-state, image, template, and styling behavior.
Behavior and rendering validation
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/*
Adds coverage for accessibility attributes, focus and events, state synchronization, options registration, item content, and class/style composition.

Demo coverage

Layer / File(s) Summary
Demo metadata and custom examples
src/BlazorUI/Demo/.../ChoiceGroup/BitChoiceGroupDemo*, *_CustomDemo*, Order.cs
Documents and demonstrates the expanded API, including descriptions, read-only behavior, gaps, events, dynamic items, icons, sizes, styling, and RTL.
Item and option demos
src/BlazorUI/Demo/.../ChoiceGroup/_BitChoiceGroup{Item,Option}Demo*
Adds matching item- and option-based examples, handlers, validation updates, and embedded sample-code revisions.

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

Suggested reviewers: yasmoradi

Poem

A rabbit hops through radios bright,
With ARIA paths aligned just right.
Gaps stretch wide and focus stays,
Descriptions guide the keyboard’s ways.
New demos bloom in soft delight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.19% 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 is concise and clearly describes the main BitChoiceGroup-focused change.
Linked Issues check ✅ Passed The PR adds missing BitChoiceGroup features, demo examples, and improved demo descriptions as requested in #12740.
Out of Scope Changes check ✅ Passed The changes stay centered on BitChoiceGroup features, demos, accessibility, and tests, with no clear unrelated additions.
✨ 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.

@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: 2

🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 374-397: Update SetInputElement’s AutoFocus branch to wrap
InputElement.FocusAsync() in defensive catches for InvalidOperationException and
JSException, preventing interop or disconnected-element failures from escaping
during rendering while preserving the existing autofocus conditions and state
updates.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs`:
- Around line 566-646: Update the second Small/Medium/Large trio in
example18RazorCode to match the live “ChoiceGroup with icon” demo: retain
Horizontal but remove Inline from each BitChoiceGroup declaration, leaving the
first inline trio 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

Run ID: d67c0345-34a4-4b60-8f99-9c941fefb8bb

📥 Commits

Reviewing files that changed from the base of the PR and between 5066e53 and 951e505.

📒 Files selected for processing (22)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs

Comment thread src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs Outdated
@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: Starting a complete review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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.

♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs (1)

376-396: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add defensive exception handling for FocusAsync.

In Blazor, calling FocusAsync can throw an InvalidOperationException (if the element is disconnected before the call completes) or a JSException (if the interop fails, e.g., due to a closed circuit). It is highly recommended to wrap FocusAsync in a try/catch block to prevent unhandled exceptions from terminating the Blazor circuit during rendering.

🛠️ Proposed fix
     internal async Task SetInputElement(TItem item, ElementReference inputElement)
     {
         var isChecked = GetIsCheckedItem(item);
 
         if (isChecked is false)
         {
             if (_items.Any(GetIsCheckedItem)) return;
             if (ReferenceEquals(_items.FirstOrDefault(), item) is false) return;
         }
 
         InputElement = inputElement;
 
         if (AutoFocus && _autoFocusDone is false && IsEnabled && ReadOnly is false && GetIsEnabled(item))
         {
             _autoFocusDone = true;
-            await InputElement.FocusAsync();
+            try
+            {
+                await InputElement.FocusAsync();
+            }
+            catch (Exception ex) when (ex is JSException || ex is InvalidOperationException)
+            {
+                // Ignore focus failures (e.g., element disconnected or hidden)
+            }
         }
     }
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`
around lines 376 - 396, Update SetInputElement so the AutoFocus FocusAsync call
is wrapped in defensive handling for InvalidOperationException and JSException,
preventing disconnected-element or failed-interop errors from escaping during
rendering while preserving the existing autofocus conditions and _autoFocusDone
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.

Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 376-396: Update SetInputElement so the AutoFocus FocusAsync call
is wrapped in defensive handling for InvalidOperationException and JSException,
preventing disconnected-element or failed-interop errors from escaping during
rendering while preserving the existing autofocus conditions and _autoFocusDone
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 621312aa-e975-4df1-a8af-117b126ddf09

📥 Commits

Reviewing files that changed from the base of the PR and between 5066e53 and 904f917.

📒 Files selected for processing (22)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs

@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: Starting a complete re-review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ Action performed

Full review finished.

@msynk

msynk commented Jul 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full-review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

@msynk: Starting a complete re-review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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.

🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss (1)

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

Stylelint: .scss extension in @import.

Flagged by Stylelint (scss/load-partial-extension). Since this convention likely repeats elsewhere in the codebase, consider a broader cleanup rather than a one-off fix here.

🤖 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/ChoiceGroup/BitChoiceGroup.scss`
at line 1, Remove the .scss extension from the `@import` in BitChoiceGroup styles,
and apply the same extensionless partial-import convention to other SCSS imports
in the affected codebase where applicable.

Source: Linters/SAST tools

src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs (1)

30-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

AutoFocus doc says "first item", but implementation skips disabled ones.

GetTabTargetItem() (Line 422) resolves to the first enabled item, falling back to the first item only when none are enabled. The XML doc here doesn't mention the "enabled" qualifier, which could mislead consumers about which item receives focus when the first item is disabled.

📝 Proposed doc fix
     /// <summary>
-    /// Determines if the ChoiceGroup is auto focused on first render, focusing its checked item (or its first item).
+    /// Determines if the ChoiceGroup is auto focused on first render, focusing its checked item (or its first enabled item).
     /// </summary>
     [Parameter] public bool AutoFocus { get; set; }
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`
around lines 30 - 34, Update the AutoFocus XML documentation to state that first
render focuses the checked item, or the first enabled item when no checked item
is available, with the existing fallback behavior for all-disabled groups
reflected accurately. Keep the implementation, parameter, and GetTabTargetItem()
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.

Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 30-34: Update the AutoFocus XML documentation to state that first
render focuses the checked item, or the first enabled item when no checked item
is available, with the existing fallback behavior for all-disabled groups
reflected accurately. Keep the implementation, parameter, and GetTabTargetItem()
behavior unchanged.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss`:
- Line 1: Remove the .scss extension from the `@import` in BitChoiceGroup styles,
and apply the same extensionless partial-import convention to other SCSS imports
in the affected codebase where applicable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dbcaec9c-9a44-490e-ae98-ceb340cb9601

📥 Commits

Reviewing files that changed from the base of the PR and between 5066e53 and 4dba0c3.

📒 Files selected for processing (31)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupAccessibilityTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupItemContentTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsApiTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStateTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStyleClassTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupUncontrolledOptionsTest.razor

@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 #12743, covering the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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: 2

🧹 Nitpick comments (4)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs (1)

31-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

AutoFocus doc doesn't match actual targeting behavior.

Doc says autofocus lands on the checked item "or its first item", but GetTabTargetItem() (Line 468) actually picks the first enabled item, falling back to the first item only when none are enabled. Worth tightening the wording so consumers aren't surprised when a disabled first item is skipped.

📝 Proposed doc fix
     /// <summary>
-    /// Determines if the ChoiceGroup is auto focused on first render, focusing its checked item (or its first item).
+    /// Determines if the ChoiceGroup is auto focused on first render, focusing its checked item (or its first enabled item, when none is checked).
     /// </summary>
     [Parameter] public bool AutoFocus { get; set; }
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`
around lines 31 - 35, Update the AutoFocus XML documentation to accurately
describe that focus targets the first enabled item, falling back to the first
item only when no enabled items exist; ensure the wording remains consistent
with GetTabTargetItem().
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs (1)

133-148: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The autofocus tests only count focus interop calls, not the target.

BitChoiceGroupShouldAutoFocusTheFirstEnabledItemWhenNothingIsChecked would pass even if the focus landed on the disabled first input — exactly the regression the comment says it guards against. Consider asserting on the invocation arguments (the element reference / id) so the intended target is actually verified.

Also applies to: 163-166

🤖 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/ChoiceGroup/BitChoiceGroupEventsTests.cs`
around lines 133 - 148, Update
BitChoiceGroupShouldAutoFocusTheFirstEnabledItemWhenNothingIsChecked and the
related test at the alternate location to assert the focus interop invocation
targets the first enabled item, using its element reference or id, rather than
only checking FocusInvocationCount(). Preserve the existing setup and ensure the
disabled first item is not the autofocus target.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor (1)

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

Guidance contradicts the sample data.

The lead says images are decorative and ImageAlt should only be set "when the picture says something the text does not", but imageItems/inlineImageItems set placeholder alts like "alt for Bar image", which duplicates the item text. Consider dropping ImageAlt from these demo items (or using it on just one item to illustrate the exception) so the example matches the advice.

🤖 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/ChoiceGroup/_BitChoiceGroupItemDemo.razor`
around lines 32 - 42, Align the demo data used by imageItems and
inlineImageItems with the accessibility guidance by removing placeholder
ImageAlt values that duplicate each item’s text. Leave ImageAlt set only on an
item where the image conveys information not present in the label, if
demonstrating that exception is needed.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor (1)

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

Prose mixes "item" and "option" on the options page.

These rewritten leads say "items" while the rest of this page (and the rendered API, BitChoiceGroupOption) says "options" — e.g. line 22 "individual items", line 47 "the item is checked … the item text", line 108 "Lays out the items in a row". Same wording appears at lines 566, 762 and 856. Worth normalizing to "option" except where the text names an actual parameter (ItemTemplate, ItemPrefixTemplate, per-item Style/Class).

Also applies to: 47-47, 108-108

🤖 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/ChoiceGroup/_BitChoiceGroupOptionDemo.razor`
at line 22, Normalize the prose in _BitChoiceGroupOptionDemo to use “option”
instead of “item” when referring to ChoiceGroup options, including the
descriptions around the disabled state, checked state/text, and layout. Preserve
“item” only when it names actual API parameters such as ItemTemplate,
ItemPrefixTemplate, or per-item Style/Class, and apply the same wording
consistently to the other noted occurrences.
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 451-466: Add defensive exception handling around FocusAsync in
SetInputElement, catching the expected JSException and InvalidOperationException
so failures from disconnected elements or closed circuits do not propagate to
the caller. Preserve the existing autofocus conditions and _autoFocusDone state
behavior.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs`:
- Around line 555-556: Correct the copied Razor sample in example20RazorCode by
inserting a space between the Label attribute and DefaultValue attribute,
keeping the rest of the BitChoiceGroup example unchanged.

---

Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 31-35: Update the AutoFocus XML documentation to accurately
describe that focus targets the first enabled item, falling back to the first
item only when no enabled items exist; ensure the wording remains consistent
with GetTabTargetItem().

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor`:
- Around line 32-42: Align the demo data used by imageItems and inlineImageItems
with the accessibility guidance by removing placeholder ImageAlt values that
duplicate each item’s text. Leave ImageAlt set only on an item where the image
conveys information not present in the label, if demonstrating that exception is
needed.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor`:
- Line 22: Normalize the prose in _BitChoiceGroupOptionDemo to use “option”
instead of “item” when referring to ChoiceGroup options, including the
descriptions around the disabled state, checked state/text, and layout. Preserve
“item” only when it names actual API parameters such as ItemTemplate,
ItemPrefixTemplate, or per-item Style/Class, and apply the same wording
consistently to the other noted occurrences.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs`:
- Around line 133-148: Update
BitChoiceGroupShouldAutoFocusTheFirstEnabledItemWhenNothingIsChecked and the
related test at the alternate location to assert the focus interop invocation
targets the first enabled item, using its element reference or id, rather than
only checking FocusInvocationCount(). Preserve the existing setup and ensure the
disabled first item is not the autofocus target.
🪄 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: a55cbb71-16b8-42d6-96bc-e668b3c64d36

📥 Commits

Reviewing files that changed from the base of the PR and between 5066e53 and fa690a8.

📒 Files selected for processing (31)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupAccessibilityTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupItemContentTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsApiTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStateTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStyleClassTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupUncontrolledOptionsTest.razor

@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 #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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: 2

♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs (1)

452-467: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Still missing defensive exception handling around FocusAsync.

This was flagged on two prior commits and remains unresolved. await InputElement.FocusAsync(); can throw JSException/JSDisconnectedException/InvalidOperationException (disconnected element, closed circuit, prerendering, etc.), and since _BitChoiceGroupItem.razor.cs's OnAfterRenderAsync awaits this method unguarded, an uncaught exception here will propagate out of the render lifecycle and can crash the circuit. The file already uses a similar guarded pattern for JS interop elsewhere (see OnAfterRenderAsync's reorder call catching JSDisconnectedException/JSException).

🛠️ Proposed fix
         if (AutoFocus && _autoFocusDone is false && IsEnabled && ReadOnly is false && GetIsEnabled(item))
         {
             _autoFocusDone = true;
-            await InputElement.FocusAsync();
+            try
+            {
+                await InputElement.FocusAsync();
+            }
+            catch (Exception ex) when (ex is JSException || ex is JSDisconnectedException || ex is InvalidOperationException)
+            {
+                // Ignore focus failures (e.g., element disconnected, circuit closed, or invalid element ref)
+            }
         }
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`
around lines 452 - 467, Wrap the InputElement.FocusAsync call in SetInputElement
with defensive exception handling for JSDisconnectedException, JSException, and
InvalidOperationException, matching the existing guarded JS interop pattern in
OnAfterRenderAsync. Ensure these expected lifecycle failures are handled locally
so they do not propagate through the render lifecycle.
🧹 Nitpick comments (1)
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs (1)

121-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert which input got focused. The test name says "the checked item", but only the invocation count is checked — it would pass if the first item were focused. FocusedElementId() is already available.

💚 Proposed tightening
-        RenderComponent<BitChoiceGroup<BitChoiceGroupItem<string>, string>>(parameters =>
+        var component = RenderComponent<BitChoiceGroup<BitChoiceGroupItem<string>, string>>(parameters =>
         {
             parameters.Add(p => p.Items, GetItems());
             parameters.Add(p => p.DefaultValue, "B");
             parameters.Add(p => p.AutoFocus, true);
         });
 
         Assert.AreEqual(1, FocusInvocationCount());
+        Assert.AreEqual(component.FindAll(".bit-chg-icn input")[1].GetAttribute("blazor:elementreference"), FocusedElementId());
🤖 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/ChoiceGroup/BitChoiceGroupEventsTests.cs`
around lines 121 - 132, Strengthen BitChoiceGroupShouldAutoFocusTheCheckedItem
by asserting that FocusedElementId() matches the input associated with the
checked/default-value item "B", in addition to the existing FocusInvocationCount
assertion. Use the existing item identifiers from GetItems() rather than only
verifying that some input received focus.
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 154-172: Add an explicit changelog or migration note for the
removed BitChoiceGroup Reversed parameter, documenting its replacement with
LabelPosition and specifying that Reversed=true in horizontal choice groups maps
to the corresponding LabelPosition value. Reference the BitChoiceGroup API and
preserve the migration guidance for existing bindings.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor`:
- Around line 313-314: Update the Prefix description in
_BitChoiceGroupCustomDemo.razor at lines 313-314 and
_BitChoiceGroupItemDemo.razor at lines 196-197 to state that Prefix renders
before the item text inside the item label, replacing the inaccurate “in front
of the radio circle” wording while keeping both pages consistent.

---

Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 452-467: Wrap the InputElement.FocusAsync call in SetInputElement
with defensive exception handling for JSDisconnectedException, JSException, and
InvalidOperationException, matching the existing guarded JS interop pattern in
OnAfterRenderAsync. Ensure these expected lifecycle failures are handled locally
so they do not propagate through the render lifecycle.

---

Nitpick comments:
In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs`:
- Around line 121-132: Strengthen BitChoiceGroupShouldAutoFocusTheCheckedItem by
asserting that FocusedElementId() matches the input associated with the
checked/default-value item "B", in addition to the existing FocusInvocationCount
assertion. Use the existing item identifiers from GetItems() rather than only
verifying that some input received focus.
🪄 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: 66a0f41d-3608-41de-bc33-3cb37def787d

📥 Commits

Reviewing files that changed from the base of the PR and between 5066e53 and 6ab55aa.

📒 Files selected for processing (31)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupAccessibilityTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupItemContentTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsApiTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStateTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStyleClassTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupUncontrolledOptionsTest.razor

@msynk

msynk commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

@msynk: Starting a re-review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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 (1)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs (1)

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

DescriptionTemplate snippet references .custom-description without defining it.

Other template examples in this file ship an inline <style> block; this one doesn't, so copy-pasting yields unstyled markup.

🤖 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/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs`
around lines 526 - 546, Update the example16RazorCode sample to include an
inline style definition for the custom-description class used by
DescriptionTemplate, matching the pattern of the other styled template examples
while preserving the existing markup and 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/ChoiceGroup/BitChoiceGroup.scss`:
- Around line 214-216: Insert a blank line immediately before the comment
describing the focus ring in the ChoiceGroup styles, without changing the
comment or surrounding selectors.

---

Nitpick comments:
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs`:
- Around line 526-546: Update the example16RazorCode sample to include an inline
style definition for the custom-description class used by DescriptionTemplate,
matching the pattern of the other styled template examples while preserving the
existing markup and 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: c8a18261-e55c-4a39-9c6c-8c9fe9e9f0ac

📥 Commits

Reviewing files that changed from the base of the PR and between fa690a8 and eddc6e1.

📒 Files selected for processing (8)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.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 review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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 (2)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs (1)

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

Inconsistent visibility: validationModel/successMessage are public here vs. private in the sibling Item demo.

No functional impact, but unnecessarily exposes page-internal demo state.

🧹 Proposed fix
-    public ChoiceGroupValidationModel validationModel = new();
-    public string? successMessage;
+    private ChoiceGroupValidationModel validationModel = new();
+    private string? successMessage;
🤖 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/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs`
around lines 27 - 28, Change the visibility of the validationModel and
successMessage fields in the choice-group option demo to private, matching the
sibling Item demo and keeping this page-internal state unexposed.
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs (1)

260-283: 🎯 Functional Correctness | 🔵 Trivial

Consider a stronger fallback for the read-only affordance.

aria-readonly on role="radiogroup" is spec-valid, but real-world AT support is inconsistent — screen readers commonly fail to announce it on radiogroups (e.g. JAWS does not output it for radiogroups per accessibility testing). Consider pairing this with a group description or visible cue so read-only state isn't silently missed by some AT users. The test itself is correct against the spec.

Sources

MDN confirms aria-readonly is used in roles including radiogroup, but independent AT testing found "JAWS: 426 aria-readonly for radiogroups is not output".

🤖 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/ChoiceGroup/BitChoiceGroupTests.cs`
around lines 260 - 283, Strengthen the read-only announcement in BitChoiceGroup
by pairing the existing aria-readonly state with a reliable accessible
description or visible read-only cue that assistive technology can announce.
Update BitChoiceGroupShouldKeepInputsReachableAndEnabledWhenReadOnly to verify
the added affordance while preserving the current input reachability,
disabled-item, and aria-readonly assertions.
🤖 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/ChoiceGroup/BitChoiceGroupDemo.razor.cs`:
- Around line 17-22: Update the AutoFocus entry in BitChoiceGroupDemo so its
Description documents the enabled-item behavior: focus the checked item when
applicable, otherwise the first enabled item, and focus nothing when the target
is disabled.

---

Nitpick comments:
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs`:
- Around line 27-28: Change the visibility of the validationModel and
successMessage fields in the choice-group option demo to private, matching the
sibling Item demo and keeping this page-internal state unexposed.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs`:
- Around line 260-283: Strengthen the read-only announcement in BitChoiceGroup
by pairing the existing aria-readonly state with a reliable accessible
description or visible read-only cue that assistive technology can announce.
Update BitChoiceGroupShouldKeepInputsReachableAndEnabledWhenReadOnly to verify
the added affordance while preserving the current input reachability,
disabled-item, and aria-readonly assertions.
🪄 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: a9a4c3e0-a5b2-4eff-80fe-8e7df6238ea3

📥 Commits

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

📒 Files selected for processing (31)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupAccessibilityTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupItemContentTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsApiTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStateTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStyleClassTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupUncontrolledOptionsTest.razor

@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 review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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

♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs (1)

469-479: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Consider also catching InvalidOperationException around FocusAsync.

JSDisconnectedException/JSException cover interop failures, but ElementReference.FocusAsync can also surface InvalidOperationException when the reference is no longer attached to a live renderer (e.g. component disposed between render and this callback). Since this runs from OnAfterRenderAsync, an escape would surface as an unhandled render exception.

🛠️ Proposed tweak
             catch (JSDisconnectedException) { } // the circuit is gone (e.g. the user navigated away), nothing to focus
             catch (JSException) { } // the element is no longer in the document, failing to focus it is not fatal
+            catch (InvalidOperationException) { } // the element reference is no longer attached to a live renderer
🤖 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/ChoiceGroup/BitChoiceGroup.razor.cs`
around lines 469 - 479, Add an InvalidOperationException catch to the FocusAsync
call in the AutoFocus handling block, alongside the existing
JSDisconnectedException and JSException catches, so detached or disposed
renderer references are treated as non-fatal.
🤖 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/ChoiceGroup/BitChoiceGroup.scss`:
- Around line 226-228: Add a blank line immediately before the double-slash
comment preceding the border-radius declaration in the ChoiceGroup styles,
leaving the comment and $shp-border-radius declaration unchanged.

---

Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs`:
- Around line 469-479: Add an InvalidOperationException catch to the FocusAsync
call in the AutoFocus handling block, alongside the existing
JSDisconnectedException and JSException catches, so detached or disposed
renderer references are treated as non-fatal.
🪄 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: 17aa2f78-ae5e-4652-97bb-a16374816111

📥 Commits

Reviewing files that changed from the base of the PR and between 826c1ad and 9c06035.

📒 Files selected for processing (31)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupAccessibilityTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupItemContentTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsApiTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStateTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStyleClassTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupUncontrolledOptionsTest.razor

@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 review of #12743, including the BitChoiceGroup implementation, accessibility behavior, tests, and demo updates.

✅ 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 (1)
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs (1)

169-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer bUnit's built-in VerifyFocusAsyncInvoke/ShouldBeElementReferenceTo over manual identifier string-matching.

FocusInvocationCount()/FocusedElementId() reinvent functionality bUnit ships out of the box specifically for testing ElementReference.FocusAsync(). Per bUnit's docs, the idiomatic pattern is JSInterop.VerifyFocusAsyncInvoke().Arguments[0].ShouldBeElementReferenceTo(inputElement), and VerifyFocusAsyncInvoke(0) / JSInterop.VerifyNotInvoke(...)-style checks cover the "not called" case. This avoids depending on an undocumented Identifier substring ("focus") and on reading the internal blazor:elementreference attribute directly.

♻️ Suggested refactor using bUnit's official API
-        // "B" is the checked item, so the focus has to land on it and not on the first one.
-        Assert.AreEqual(1, FocusInvocationCount());
-        Assert.AreEqual(component.FindAll(".bit-chg-icn input")[items.FindIndex(i => i.Value == "B")].GetAttribute("blazor:elementreference"), FocusedElementId());
+        // "B" is the checked item, so the focus has to land on it and not on the first one.
+        var expectedInput = component.FindAll(".bit-chg-icn input")[items.FindIndex(i => i.Value == "B")];
+        Context.JSInterop.VerifyFocusAsyncInvoke().Arguments[0].ShouldBeElementReferenceTo(expectedInput);
-    private int FocusInvocationCount()
-    {
-        return Context.JSInterop.Invocations.Count(i => i.Identifier.Contains("focus", System.StringComparison.OrdinalIgnoreCase));
-    }
-
-    // The id of the element the focus interop was called with, so a test can assert which input was focused
-    // and not only that something was. It matches the blazor:elementreference attribute bUnit renders on the
-    // elements captured with `@ref`.
-    private string FocusedElementId()
-    {
-        var invocation = Context.JSInterop.Invocations.Single(i => i.Identifier.Contains("focus", System.StringComparison.OrdinalIgnoreCase));
-
-        return ((ElementReference)invocation.Arguments[0]!).Id;
-    }
🤖 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/ChoiceGroup/BitChoiceGroupEventsTests.cs`
around lines 169 - 182, Replace the manual FocusInvocationCount and
FocusedElementId helpers with bUnit’s built-in JSInterop verification APIs.
Update the affected ChoiceGroup tests to use VerifyFocusAsyncInvoke,
VerifyNotInvoke, and ShouldBeElementReferenceTo for focus-call and target
assertions, removing Identifier substring matching and direct ElementReference
ID inspection.
🤖 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/ChoiceGroup/BitChoiceGroupItem.cs`:
- Around line 93-97: Revise the Title XML documentation for BitChoiceGroupItem
and BitChoiceGroupOption to state that AriaLabel provides an alternative
accessible name, not visible content; direct required information to
Text/templates or Description. Align the corresponding item and option API
metadata in BitChoiceGroupDemo.razor.cs at the specified ranges with the same
guidance.

---

Nitpick comments:
In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs`:
- Around line 169-182: Replace the manual FocusInvocationCount and
FocusedElementId helpers with bUnit’s built-in JSInterop verification APIs.
Update the affected ChoiceGroup tests to use VerifyFocusAsyncInvoke,
VerifyNotInvoke, and ShouldBeElementReferenceTo for focus-call and target
assertions, removing Identifier substring matching and direct ElementReference
ID inspection.
🪄 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: c02e5ac6-920d-4ebd-a225-7fe21258c4db

📥 Commits

Reviewing files that changed from the base of the PR and between 59c2556 and c209bb5.

📒 Files selected for processing (32)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroup.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupNameSelectors.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/_BitChoiceGroupItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/Order.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupCustomDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupItemDemo.razor.samples.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/_BitChoiceGroupOptionDemo.razor.samples.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupAccessibilityTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupEventsTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupItemContentTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsApiTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStateTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupStyleClassTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/ChoiceGroup/BitChoiceGroupUncontrolledOptionsTest.razor
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Utils/Theme/component-css-variables.md

Comment on lines +93 to +97
/// <summary>
/// The title attribute (the native tooltip) of the BitChoiceGroup item. This is supplementary text only:
/// use <see cref="AriaLabel"/> or <see cref="Description"/> for content that has to reach every user.
/// </summary>
public string? Title { get; set; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the Title accessibility guidance.

AriaLabel supplies an accessible name, not visible content, so it cannot make required information reach every user. Direct required visible content to Text/templates or Description; reserve AriaLabel for an alternative accessible name.

  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs#L93-L97: revise the XML documentation.
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs#L101-L105: revise the matching XML documentation.
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs#L542-L546: align item API metadata.
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs#L692-L696: align option API metadata.
📍 Affects 3 files
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupItem.cs#L93-L97 (this comment)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/ChoiceGroup/BitChoiceGroupOption.cs#L101-L105
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs#L542-L546
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/ChoiceGroup/BitChoiceGroupDemo.razor.cs#L692-L696
🤖 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/ChoiceGroup/BitChoiceGroupItem.cs`
around lines 93 - 97, Revise the Title XML documentation for BitChoiceGroupItem
and BitChoiceGroupOption to state that AriaLabel provides an alternative
accessible name, not visible content; direct required information to
Text/templates or Description. Align the corresponding item and option API
metadata in BitChoiceGroupDemo.razor.cs at the specified ranges with the same
guidance.

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 BitChoiceGroup improvements

2 participants