MudCheckBox, MudSwitch, MudRadio: Respect user-defined tabindex#12808
MudCheckBox, MudSwitch, MudRadio: Respect user-defined tabindex#12808danielchalmers merged 2 commits intoMudBlazor:devfrom
tabindex#12808Conversation
…`, and `MudRadio` This fixes a `tabindex` precedence issue on boolean inputs where user-supplied `tabindex` values could be ignored. `MudCheckBox`, `MudSwitch`, and `MudRadio` were applying a default `tabindex` directly on the internal `<input>`, which could override user intent in some scenarios. Now, user-provided `tabindex` is respected. ## Root Cause The components combined `@attributes="UserAttributes"` with an explicit `tabindex="..."` on the same `<input>`, causing conflicting precedence behavior. ## Changes - Added shared input attribute resolution in `MudBooleanInput<T>`: - `GetInputAttributes()` - Sets default `tabindex` (`0` enabled / `-1` disabled) - Merges `UserAttributes` after defaults - Uses case-insensitive keys (`StringComparer.OrdinalIgnoreCase`) so `tabindex` overrides are reliable - Updated: - `MudCheckBox` input markup to use `@attributes="GetInputAttributes()"` - `MudSwitch` input markup to use `@attributes="GetInputAttributes()"` - `MudRadio` input markup to use `@attributes="GetInputAttributes()"`
tabindex on root elementtabindex
|
|
||
| foreach (var userAttribute in UserAttributes) | ||
| { | ||
| attributes[userAttribute.Key] = userAttribute.Value; |
There was a problem hiding this comment.
This would override the -1 on a disabled field if a UserAttribute includes a tabindex value.
Is this intentional? The previous solution worked differently
There was a problem hiding this comment.
Yes, so the user's parameter always wins
There was a problem hiding this comment.
I guess we aren't the ARIA police but it just feels wrong to let it be tabbable if disabled lol.
There was a problem hiding this comment.
The disabled attribute should still prevents focus/interaction. So overriding tabindex there mainly affects rendered markup, not actual keyboard accessibility behavior.
There was a problem hiding this comment.
Pull request overview
This PR fixes tabindex precedence for boolean input components so user-supplied tabindex values are not overridden by component defaults, addressing reported keyboard navigation issues in MudCheckBox, MudSwitch, and MudRadio.
Changes:
- Centralized input attribute resolution in
MudBooleanInput<T>viaGetInputAttributes()with defaulttabindexand case-insensitive merging ofUserAttributes. - Updated
MudCheckBox,MudSwitch, andMudRadioinput markup to use@attributes="GetInputAttributes()"(removing hard-codedtabindexfrom the<input>). - Added unit tests for checkbox/switch/radio to verify default, disabled, and custom (case-insensitive)
tabindexbehavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/MudBlazor/Base/MudBooleanInput.cs | Adds shared GetInputAttributes() that applies a default tabindex and merges UserAttributes case-insensitively so user overrides win reliably. |
| src/MudBlazor/Components/CheckBox/MudCheckBox.razor | Switches <input> attribute splatting to GetInputAttributes() to ensure custom tabindex is respected. |
| src/MudBlazor/Components/Switch/MudSwitch.razor | Switches <input> attribute splatting to GetInputAttributes() to ensure custom tabindex is respected. |
| src/MudBlazor/Components/Radio/MudRadio.razor | Switches <input> attribute splatting to GetInputAttributes() to ensure custom tabindex is respected. |
| src/MudBlazor.UnitTests/Components/CheckBoxTests.cs | Adds tests for default/disabled/custom/case-insensitive tabindex behavior. |
| src/MudBlazor.UnitTests/Components/SwitchTests.cs | Adds tests for default/disabled/custom/case-insensitive tabindex behavior. |
| src/MudBlazor.UnitTests/Components/RadioTests.cs | Adds tests for default/disabled/custom/case-insensitive tabindex behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ["tabindex"] = GetDisabledState() ? -1 : 0 | ||
| }; | ||
|
|
||
| foreach (var userAttribute in UserAttributes) |
There was a problem hiding this comment.
What happens if UserAttributes is null? Won't that create an exception?
There was a problem hiding this comment.
Not in normal usage.
UserAttributesis initialized inMudComponentBaseas a non-null empty dictionary:So when no unmatched attributes are provided, it’s
{}and theforeachis safe.Also, this isn’t a new assumption from this change; MudBlazor already uses
UserAttributesas non-null in multiple places (for exampleFieldIdusesUserAttributes.TryGetValue(...)directly).
This fixes a
tabindexprecedence issue on boolean inputs where user-suppliedtabindexvalues could be ignored.MudCheckBox,MudSwitch, andMudRadiowere applying a defaulttabindexdirectly on the internal<input>, which could override user intent in some scenarios. Now, user-providedtabindexis respected.Changes:
MudBooleanInput<T>:GetInputAttributes()tabindex(0enabled /-1disabled)UserAttributesafter defaultsStringComparer.OrdinalIgnoreCase) sotabindexoverrides are reliableMudCheckBoxinput markup to use@attributes="GetInputAttributes()"MudSwitchinput markup to use@attributes="GetInputAttributes()"MudRadioinput markup to use@attributes="GetInputAttributes()"Closes #7346 and Closes #12800
Checklist: