66 * found in the LICENSE file at https://angular.io/license
77 */
88
9+ import { FocusMonitor , FocusOrigin } from '@angular/cdk/a11y' ;
10+ import { UniqueSelectionDispatcher } from '@angular/cdk/collections' ;
911import {
12+ ANIMATION_MODULE_TYPE ,
1013 AfterContentInit ,
1114 AfterViewInit ,
1215 Attribute ,
13- booleanAttribute ,
1416 ChangeDetectionStrategy ,
1517 ChangeDetectorRef ,
1618 Component ,
@@ -19,24 +21,25 @@ import {
1921 DoCheck ,
2022 ElementRef ,
2123 EventEmitter ,
22- forwardRef ,
2324 Inject ,
2425 InjectionToken ,
26+ Injector ,
2527 Input ,
26- numberAttribute ,
2728 OnDestroy ,
2829 OnInit ,
2930 Optional ,
3031 Output ,
3132 QueryList ,
3233 ViewChild ,
3334 ViewEncapsulation ,
34- ANIMATION_MODULE_TYPE ,
35+ afterNextRender ,
36+ booleanAttribute ,
37+ forwardRef ,
38+ inject ,
39+ numberAttribute ,
3540} from '@angular/core' ;
36- import { _MatInternalFormField , MatRipple , ThemePalette } from '@angular/material/core' ;
37- import { FocusMonitor , FocusOrigin } from '@angular/cdk/a11y' ;
38- import { UniqueSelectionDispatcher } from '@angular/cdk/collections' ;
3941import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
42+ import { MatRipple , ThemePalette , _MatInternalFormField } from '@angular/material/core' ;
4043import { Subscription } from 'rxjs' ;
4144
4245// Increasing integer for generating unique ids for radio components.
@@ -532,6 +535,8 @@ export class MatRadioButton implements OnInit, AfterViewInit, DoCheck, OnDestroy
532535 /** Whether animations are disabled. */
533536 _noopAnimations : boolean ;
534537
538+ private _injector = inject ( Injector ) ;
539+
535540 constructor (
536541 @Optional ( ) @Inject ( MAT_RADIO_GROUP ) radioGroup : MatRadioGroup ,
537542 protected _elementRef : ElementRef ,
@@ -695,6 +700,29 @@ export class MatRadioButton implements OnInit, AfterViewInit, DoCheck, OnDestroy
695700 if ( input ) {
696701 input . setAttribute ( 'tabindex' , value + '' ) ;
697702 this . _previousTabIndex = value ;
703+ // Wait for any pending tabindex changes to be applied
704+ afterNextRender (
705+ ( ) => {
706+ // The radio group uses a "selection follows focus" pattern for tab management, so if this
707+ // radio button is currently focused and another radio button in the group becomes
708+ // selected, we should move focus to the newly selected radio button to maintain
709+ // consistency between the focused and selected states.
710+ if (
711+ group &&
712+ group . selected &&
713+ group . selected !== this &&
714+ document . activeElement === input
715+ ) {
716+ group . selected ?. _inputElement . nativeElement . focus ( ) ;
717+ // If this radio button still has focus, the selected one must be disabled. In this
718+ // case the radio group as a whole should lose focus.
719+ if ( document . activeElement === input ) {
720+ this . _inputElement . nativeElement . blur ( ) ;
721+ }
722+ }
723+ } ,
724+ { injector : this . _injector } ,
725+ ) ;
698726 }
699727 }
700728 }
0 commit comments