Bläddra i källkod

Fix combobox accessibility

Caleb Porzio 2 år sedan
förälder
incheckning
32e97f0f74

+ 3 - 2
packages/ui/src/combobox.js

@@ -397,7 +397,7 @@ function handleOptions(el, Alpine) {
         ':id'() { return this.$id('alpine-combobox-options') },
         ':id'() { return this.$id('alpine-combobox-options') },
 
 
         // Accessibility attributes...
         // Accessibility attributes...
-        'role': 'combobox',
+        'role': 'listbox',
         ':aria-labelledby'() { return this.$refs.__label ? this.$refs.__label.id : (this.$refs.__button ? this.$refs.__button.id : null) },
         ':aria-labelledby'() { return this.$refs.__label ? this.$refs.__label.id : (this.$refs.__button ? this.$refs.__button.id : null) },
 
 
         // Initialize...
         // Initialize...
@@ -422,7 +422,8 @@ function handleOption(el, Alpine) {
         // Accessibility attributes...
         // Accessibility attributes...
         'role': 'option',
         'role': 'option',
         ':tabindex'() { return this.$comboboxOption.isDisabled ? undefined : '-1' },
         ':tabindex'() { return this.$comboboxOption.isDisabled ? undefined : '-1' },
-        ':aria-selected'() { return this.$comboboxOption.isActive },
+        // Only the active element should have aria-selected="true"...
+        'x-effect'() { this.$comboboxOption.isActive ? el.setAttribute('aria-selected', true) : el.removeAttribute('aria-selected') },
         ':aria-disabled'() { return this.$comboboxOption.isDisabled },
         ':aria-disabled'() { return this.$comboboxOption.isDisabled },
 
 
         // Initialize...
         // Initialize...

+ 4 - 4
tests/cypress/integration/plugins/ui/combobox.spec.js

@@ -822,7 +822,7 @@ test('has accessibility attributes',
             .should(haveAttribute('aria-controls', 'alpine-combobox-options-1'))
             .should(haveAttribute('aria-controls', 'alpine-combobox-options-1'))
 
 
         get('[options]')
         get('[options]')
-            .should(haveAttribute('role', 'combobox'))
+            .should(haveAttribute('role', 'listbox'))
             .should(haveAttribute('id', 'alpine-combobox-options-1'))
             .should(haveAttribute('id', 'alpine-combobox-options-1'))
             .should(haveAttribute('aria-labelledby', 'alpine-combobox-label-1'))
             .should(haveAttribute('aria-labelledby', 'alpine-combobox-label-1'))
 
 
@@ -836,7 +836,7 @@ test('has accessibility attributes',
             .should(haveAttribute('role', 'option'))
             .should(haveAttribute('role', 'option'))
             .should(haveAttribute('id', 'alpine-combobox-option-2'))
             .should(haveAttribute('id', 'alpine-combobox-option-2'))
             .should(haveAttribute('tabindex', '-1'))
             .should(haveAttribute('tabindex', '-1'))
-            .should(haveAttribute('aria-selected', 'false'))
+            .should(notHaveAttribute('aria-selected'))
 
 
         get('input')
         get('input')
             .should(haveAttribute('role', 'combobox'))
             .should(haveAttribute('role', 'combobox'))
@@ -1206,7 +1206,7 @@ test('active element logic when opening a combobox',
         get('ul').should(beVisible())
         get('ul').should(beVisible())
         get('[option="1"]').should(haveAttribute('aria-selected', 'true'))
         get('[option="1"]').should(haveAttribute('aria-selected', 'true'))
         // First match is selected while typing
         // First match is selected while typing
-        get('[option="4"]').should(haveAttribute('aria-selected', 'false'))
+        get('[option="4"]').should(notHaveAttribute('aria-selected'))
         get('input').type('T')
         get('input').type('T')
         get('input').trigger('change')
         get('input').trigger('change')
         get('[option="4"]').should(haveAttribute('aria-selected', 'true'))
         get('[option="4"]').should(haveAttribute('aria-selected', 'true'))
@@ -1216,7 +1216,7 @@ test('active element logic when opening a combobox',
         get('[option="3"]').click()
         get('[option="3"]').click()
         // Previous selection is selected
         // Previous selection is selected
         get('button').click()
         get('button').click()
-        get('[option="4"]').should(haveAttribute('aria-selected', 'false'))
+        get('[option="4"]').should(notHaveAttribute('aria-selected'))
         get('[option="3"]').should(haveAttribute('aria-selected', 'true'))
         get('[option="3"]').should(haveAttribute('aria-selected', 'true'))
     }
     }
 )
 )