Component
RadioGroup
Package version
3.0.0-rc.20
@microsoft/fast-element version
2.10.4
Environment
System:
OS: macOS 26.4.1
CPU: (8) arm64 Apple M3
Memory: 298.63 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Browsers:
Chrome: 148.0.7778.97
Edge: 148.0.3967.83
Firefox: 150.0.1
Safari: 26.4
Current Behavior
When BaseRadioGroup.slottedRadiosChanged runs before slotted <fluent-radio> elements have been upgraded (e.g. RadioGroupDefinition.define() is called before RadioDefinition.define()), the radio group collects bare HTMLElement nodes into this.radios.
// radio-group.base.ts
slottedRadiosChanged(prev, next) {
this.radios = [...this.querySelectorAll('*')].filter(x => isRadio(x));
}
isRadio is a tag-name suffix check (-radio) inherited from isCustomElement, so it matches elements regardless of upgrade state:
export function isCustomElement(tagSuffix) {
return (element) =>
element?.nodeType === Node.ELEMENT_NODE &&
element.tagName.toLowerCase().endsWith(tagSuffix);
}
Downstream radiosChanged then synchronously writes .checked (and name, disabled, etc.) on each entry. Because these targets are still bare HTMLElements, the assignments become own data properties on the instance. When the element later upgrades to Radio, those own data properties permanently shadow the inherited BaseCheckbox.checked accessor — so every subsequent write through the setter is silently dropped:
:state(checked) is never added → indicator dot never paints
setFormValue is never called → no form participation
setAriaChecked is never called → broken aria-checked
Observable.notify('checked') is never called → no change propagation
Regression history
The previous implementation filtered with instanceof Radio (which is false for unupgraded elements) and deferred collection via Updates.enqueue. A refactor replaced both — switching to the isRadio tag check and removing the deferral — which is what introduced this race.
Expected Behavior
RadioGroup should never write to elements that haven't upgraded yet, because doing so corrupts their prototype chain once they do.
Reproduction
https://stackblitz.com/edit/vitejs-vite-jwyknbey?file=src%2Fmain.ts
Steps to reproduce
- Go to Stackblitz repro
- See that radio Option 2 should be checked according to the code
- Observe that Option 2 is not checked in the rendered control
Are you reporting an Accessibility issue?
None
Suggested severity
Urgent - No workaround and Products/sites are affected
Products/sites affected
Fabric UX and Power BI
Are you willing to submit a PR to fix?
yes
Validations
Component
RadioGroup
Package version
3.0.0-rc.20
@microsoft/fast-element version
2.10.4
Environment
System: OS: macOS 26.4.1 CPU: (8) arm64 Apple M3 Memory: 298.63 MB / 16.00 GB Shell: 5.9 - /bin/zsh Browsers: Chrome: 148.0.7778.97 Edge: 148.0.3967.83 Firefox: 150.0.1 Safari: 26.4Current Behavior
When
BaseRadioGroup.slottedRadiosChangedruns before slotted<fluent-radio>elements have been upgraded (e.g.RadioGroupDefinition.define()is called beforeRadioDefinition.define()), the radio group collects bareHTMLElementnodes intothis.radios.isRadiois a tag-name suffix check (-radio) inherited fromisCustomElement, so it matches elements regardless of upgrade state:Downstream
radiosChangedthen synchronously writes.checked(andname,disabled, etc.) on each entry. Because these targets are still bareHTMLElements, the assignments become own data properties on the instance. When the element later upgrades toRadio, those own data properties permanently shadow the inheritedBaseCheckbox.checkedaccessor — so every subsequent write through the setter is silently dropped::state(checked)is never added → indicator dot never paintssetFormValueis never called → no form participationsetAriaCheckedis never called → brokenaria-checkedObservable.notify('checked')is never called → no change propagationRegression history
The previous implementation filtered with
instanceof Radio(which isfalsefor unupgraded elements) and deferred collection viaUpdates.enqueue. A refactor replaced both — switching to theisRadiotag check and removing the deferral — which is what introduced this race.Expected Behavior
RadioGroupshould never write to elements that haven't upgraded yet, because doing so corrupts their prototype chain once they do.Reproduction
https://stackblitz.com/edit/vitejs-vite-jwyknbey?file=src%2Fmain.ts
Steps to reproduce
Are you reporting an Accessibility issue?
None
Suggested severity
Urgent - No workaround and Products/sites are affected
Products/sites affected
Fabric UX and Power BI
Are you willing to submit a PR to fix?
yes
Validations