@@ -262,13 +262,21 @@ export class Checkbox implements ComponentInterface {
262262
263263 renderHiddenInput ( true , el , name , checked ? value : '' , disabled ) ;
264264
265+ // Determine appropriate accessible name
266+ const hasLabelContent = el . textContent !== '' ;
267+ const hasLabelId = inputId + '-lbl' ;
268+
265269 return (
270+ /*
271+ The host must be a checkbox role to support Safari's Voice Over accessibility
272+ */
266273 < Host
267274 role = "checkbox"
268275 aria-checked = { indeterminate ? 'mixed' : `${ checked } ` }
269276 aria-describedby = { this . getHintTextID ( ) }
270277 aria-invalid = { this . getHintTextID ( ) === this . errorTextId }
271- aria-labelledby = { inputId + '-lbl' }
278+ aria-labelledby = { hasLabelContent ? hasLabelId : null }
279+ aria-label = { ! hasLabelContent ? inheritedAttributes [ 'aria-label' ] || 'checkbox' : null }
272280 aria-disabled = { disabled ? 'true' : null }
273281 tabindex = "0"
274282 onKeyDown = { this . onKeyDown }
@@ -289,11 +297,12 @@ export class Checkbox implements ComponentInterface {
289297 { /*
290298 The native control must be rendered
291299 before the visible label text due to https://bugs.webkit.org/show_bug.cgi?id=251951
300+ and it must be hidden with display:none instead of aria-hidden="true"
301+ to avoid nested interactive elements accessibility issues
292302 */ }
293303 < input
294304 type = "checkbox"
295- aria-hidden = "true"
296- tabindex = "-1"
305+ style = { { display : 'none' } }
297306 checked = { checked ? true : undefined }
298307 disabled = { disabled }
299308 id = { inputId }
@@ -307,10 +316,10 @@ export class Checkbox implements ComponentInterface {
307316 < div
308317 class = { {
309318 'label-text-wrapper' : true ,
310- 'label-text-wrapper-hidden' : el . textContent === '' ,
319+ 'label-text-wrapper-hidden' : ! hasLabelContent ,
311320 } }
312321 part = "label"
313- id = { inputId + '-lbl' }
322+ id = { hasLabelId }
314323 >
315324 < slot > </ slot >
316325 { this . renderHintText ( ) }
0 commit comments