@@ -30,18 +30,21 @@ export class PlanPreview {
30
30
31
31
// Find the corresponding radio input
32
32
let radioInput = null
33
+ let radioLabel = null
33
34
34
35
// First structure (original page)
35
36
const templateRow = this . node . closest ( '.plan-template__row' )
36
37
if ( templateRow ) {
37
38
radioInput = templateRow . querySelector ( '.radio__input' )
39
+ radioLabel = templateRow . querySelector ( '.radio__label' )
38
40
}
39
41
40
42
// Second structure (choice-list page)
41
43
if ( ! radioInput ) {
42
44
const choiceListItem = this . node . closest ( '.choice-list__item' )
43
45
if ( choiceListItem ) {
44
46
radioInput = choiceListItem . querySelector ( '.choice-list__radio' )
47
+ radioLabel = choiceListItem . querySelector ( '.choice-list__label' )
45
48
}
46
49
}
47
50
@@ -51,6 +54,18 @@ export class PlanPreview {
51
54
// As a fallback, try to find the radio by its ID
52
55
if ( ! radioInput && templateId ) {
53
56
radioInput = document . getElementById ( `id_template_${ templateId } ` )
57
+ if ( radioInput ) {
58
+ // Try to find the associated label
59
+ radioLabel = document . querySelector (
60
+ `label[for="id_template_${ templateId } "]`
61
+ )
62
+ if ( ! radioLabel ) {
63
+ // If no explicit label found, look for parent or ancestor label
64
+ radioLabel =
65
+ radioInput . closest ( 'label' ) ||
66
+ radioInput . parentElement . querySelector ( 'label' )
67
+ }
68
+ }
54
69
}
55
70
56
71
// Find all close buttons in the modal
@@ -67,6 +82,9 @@ export class PlanPreview {
67
82
// Select the radio input
68
83
radioInput . checked = true
69
84
85
+ // Set focus to the radio input to trigger CSS focus styles
86
+ radioInput . focus ( )
87
+
70
88
// If using the choice-list structure, add the 'selected' class to the parent list item
71
89
const choiceListItem = radioInput . closest ( '.choice-list__item' )
72
90
if ( choiceListItem ) {
@@ -81,15 +99,38 @@ export class PlanPreview {
81
99
// Trigger change event to ensure any listeners know the radio was changed
82
100
const changeEvent = new Event ( 'change' , { bubbles : true } )
83
101
radioInput . dispatchEvent ( changeEvent )
102
+
103
+ // Add a small delay before setting focus to ensure DOM updates are processed
104
+ setTimeout ( ( ) => {
105
+ // For the first HTML variant, ensure focus affects the label for visual feedback
106
+ if ( radioInput && radioLabel && templateRow ) {
107
+ // First try to focus the label if possible (better for accessibility)
108
+ if ( radioLabel . getAttribute ( 'for' ) === radioInput . id ) {
109
+ radioLabel . focus ( )
110
+ } else {
111
+ // Otherwise focus the input itself
112
+ radioInput . focus ( )
113
+ }
114
+ }
115
+ } , 50 )
84
116
} ,
85
117
{ once : true }
86
118
)
87
119
} )
88
120
}
89
121
90
- // Set the modal-closed callback to focus on the element that opened it
122
+ // Set the modal-closed callback to focus on the selected radio or label
91
123
modal . setModalClosedCallback ( ( ) => {
92
- if ( modal . openedBy ) {
124
+ if ( radioInput && radioInput . checked ) {
125
+ // Try to focus the label first (if it exists and is properly linked)
126
+ if ( radioLabel && radioLabel . getAttribute ( 'for' ) === radioInput . id ) {
127
+ radioLabel . focus ( )
128
+ } else {
129
+ // Fall back to focusing the input itself
130
+ radioInput . focus ( )
131
+ }
132
+ } else if ( modal . openedBy ) {
133
+ // If no radio was selected, return focus to the element that opened the modal
93
134
modal . openedBy . focus ( )
94
135
}
95
136
} )
0 commit comments