diff --git a/examples/index.html b/examples/index.html
index 0bc36d6..48e7ec3 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -3,49 +3,60 @@
details-menu demo
+
Best robot: Unknown
-
-
-
-
-
+
+
+
Best robot: Unknown
-
+
+
+
Favorite robots
-
+
+
+
Favorite robots
-
-
-
-
-
+
+
+
diff --git a/index.js b/index.js
index cdc2563..9a550ca 100644
--- a/index.js
+++ b/index.js
@@ -26,13 +26,16 @@ class DetailsMenuElement extends HTMLElement {
}
connectedCallback() {
- this.setAttribute('role', 'menu')
+ if (!this.hasAttribute('role')) this.setAttribute('role', 'menu')
const details = this.parentElement
if (!details) return
const summary = details.querySelector('summary')
- if (summary) summary.setAttribute('aria-haspopup', 'menu')
+ if (summary) {
+ summary.setAttribute('aria-haspopup', 'menu')
+ if (!summary.hasAttribute('role')) summary.setAttribute('role', 'button')
+ }
details.addEventListener('click', shouldCommit)
details.addEventListener('change', shouldCommit)
@@ -96,10 +99,9 @@ function focusOnOpen(details: Element) {
const onmousedown = () => (isMouse = true)
const onkeydown = () => (isMouse = false)
const ontoggle = () => {
- autofocus(details)
- if (details.hasAttribute('open') && !isMouse) {
- focusFirstItem(details)
- }
+ if (!details.hasAttribute('open')) return
+ if (autofocus(details)) return
+ if (!isMouse) focusFirstItem(details)
}
details.addEventListener('mousedown', onmousedown)
@@ -128,12 +130,14 @@ function closeCurrentMenu(event: Event) {
}
}
-function autofocus(details: Element) {
- if (!details.hasAttribute('open')) return
-
+function autofocus(details: Element): boolean {
+ if (!details.hasAttribute('open')) return false
const input = details.querySelector('[autofocus]')
if (input) {
input.focus()
+ return true
+ } else {
+ return false
}
}
diff --git a/test/test.js b/test/test.js
index 72a019f..bd4d4ab 100644
--- a/test/test.js
+++ b/test/test.js
@@ -34,6 +34,14 @@ describe('details-menu element', function() {
document.body.innerHTML = ''
})
+ it('has default attributes set', function() {
+ const details = document.querySelector('details')
+ const summary = details.querySelector('summary')
+ const menu = details.querySelector('details-menu')
+ assert.equal(summary.getAttribute('role'), 'button')
+ assert.equal(menu.getAttribute('role'), 'menu')
+ })
+
it('opens and does not focus an item on mouse click', function() {
const details = document.querySelector('details')
const summary = details.querySelector('summary')
@@ -546,6 +554,55 @@ describe('details-menu element', function() {
})
})
+ describe('with input[autofocus]', function() {
+ beforeEach(function() {
+ const container = document.createElement('div')
+ container.innerHTML = `
+
+ Menu 1
+
+
+
+
+
+
+
+ `
+ document.body.append(container)
+ })
+
+ afterEach(function() {
+ document.body.innerHTML = ''
+ })
+
+ it('autofocuses on input on mouse click', function() {
+ const details = document.querySelector('details')
+ const summary = details.querySelector('summary')
+ const menu = details.querySelector('details-menu')
+ const input = details.querySelector('input')
+
+ summary.focus()
+ details.open = true
+ summary.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}))
+ details.dispatchEvent(new CustomEvent('toggle'))
+ assert.equal(menu.getAttribute('role'), 'none')
+ assert.equal(input, document.activeElement, 'mouse toggle open leaves summary focused')
+ })
+
+ it('autofocuses on input on keyboard activation', function() {
+ const details = document.querySelector('details')
+ const summary = details.querySelector('summary')
+ const input = details.querySelector('input')
+
+ summary.focus()
+ details.open = true
+ summary.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter', bubbles: true}))
+ details.dispatchEvent(new CustomEvent('toggle'))
+
+ assert.equal(input, document.activeElement, 'toggle open focuses on [autofocus]')
+ })
+ })
+
describe('closing the menu', function() {
beforeEach(function() {
const container = document.createElement('div')