diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js index accda175b9..27f1c10385 100644 --- a/examples/combobox/js/combobox-autocomplete.js +++ b/examples/combobox/js/combobox-autocomplete.js @@ -57,7 +57,12 @@ class ComboboxAutocomplete { 'focus', this.onComboboxFocus.bind(this) ); - this.comboboxNode.addEventListener('blur', this.onComboboxBlur.bind(this)); + + document.body.addEventListener( + 'mouseup', + this.onBackgroundMouseUp.bind(this), + true + ); // initialize pop up menu @@ -507,11 +512,17 @@ class ComboboxAutocomplete { this.setCurrentOptionStyle(null); } - onComboboxBlur() { - this.comboboxHasVisualFocus = false; - this.setCurrentOptionStyle(null); - this.removeVisualFocusAll(); - setTimeout(this.close.bind(this, false), 300); + onBackgroundMouseUp(event) { + if ( + !this.comboboxNode.contains(event.target) && + !this.listboxNode.contains(event.target) && + !this.buttonNode.contains(event.target) + ) { + this.comboboxHasVisualFocus = false; + this.setCurrentOptionStyle(null); + this.removeVisualFocusAll(); + setTimeout(this.close.bind(this, true), 300); + } } onButtonClick() { @@ -563,7 +574,6 @@ window.addEventListener('load', function () { var comboboxNode = combobox.querySelector('input'); var buttonNode = combobox.querySelector('button'); var listboxNode = combobox.querySelector('[role="listbox"]'); - var cba = new ComboboxAutocomplete(comboboxNode, buttonNode, listboxNode); - cba.init(); + new ComboboxAutocomplete(comboboxNode, buttonNode, listboxNode); } }); diff --git a/test/tests/combobox_autocomplete-list.js b/test/tests/combobox_autocomplete-list.js index f14e3e578c..18400a0e54 100644 --- a/test/tests/combobox_autocomplete-list.js +++ b/test/tests/combobox_autocomplete-list.js @@ -14,6 +14,7 @@ const ex = { optionsSelector: '#ex1 [role="option"]', buttonSelector: '#ex1 button', numAOptions: 5, + exampleHeadingSelector: '.example-header', }; const waitForFocusChange = async (t, textboxSelector, originalFocus) => { @@ -850,6 +851,92 @@ ariaTest( } ); +ariaTest( + 'Clicking outside of textbox and listbox when focus is on listbox closes listbox', + exampleFile, + 'test-additional-behavior', + async (t) => { + // Send key "a" to open listbox then key "ARROW_DOWN" to put the focus on the listbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_DOWN); + + // click outside the listbox + await t.context.session + .findElement(By.css(ex.exampleHeadingSelector)) + .click(); + + await t.context.session.wait( + async function () { + let listbox = await t.context.session.findElement( + By.css(ex.listboxSelector) + ); + return !(await listbox.isDisplayed()); + }, + t.context.waitTime, + 'Error waiting for listbox to close after outside click' + ); + + // Confirm the listbox is closed and the textbox is cleared + await assertAttributeValues( + t, + ex.textboxSelector, + 'aria-expanded', + 'false' + ); + t.is( + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('value'), + 'a', + 'Click outside of a textbox will close the textbox without selecting the highlighted value' + ); + } +); + +ariaTest( + 'Clicking outside of textbox and listbox when focus is on textbox closes listbox', + exampleFile, + 'test-additional-behavior', + async (t) => { + // Send key "a" to open listbox to put focus on textbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a'); + + // click outside the listbox + await t.context.session + .findElement(By.css(ex.exampleHeadingSelector)) + .click(); + + await t.context.session.wait( + async function () { + let listbox = await t.context.session.findElement( + By.css(ex.listboxSelector) + ); + return !(await listbox.isDisplayed()); + }, + t.context.waitTime, + 'Error waiting for listbox to close after outside click' + ); + + // Confirm the listbox is closed and the textbox is cleared + await assertAttributeValues( + t, + ex.textboxSelector, + 'aria-expanded', + 'false' + ); + t.is( + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('value'), + 'a', + 'Click outside of a textbox will close the textbox without selecting the highlighted value' + ); + } +); + ariaTest( 'left arrow from focus on list puts focus on listbox and moves cursor right', exampleFile,