diff --git a/docs/pages/resources/changelog.md b/docs/pages/resources/changelog.md index e4dab556..92668385 100644 --- a/docs/pages/resources/changelog.md +++ b/docs/pages/resources/changelog.md @@ -12,6 +12,10 @@ Components with the Experimental bad New versions of Shoelace are released as-needed and generally occur when a critical mass of changes have accumulated. At any time, you can see what's coming in the next release by visiting [next.shoelace.style](https://next.shoelace.style). +## Next + +- Fixed accessibility issues for elements that are closed while having slotted focused children. + ## 2.20.0 - Added the ability to set a custom snap function and use `repeat(n)` to `` [#2340] diff --git a/src/components/alert/alert.component.ts b/src/components/alert/alert.component.ts index 2f2ffbd9..7b442cd6 100644 --- a/src/components/alert/alert.component.ts +++ b/src/components/alert/alert.component.ts @@ -1,4 +1,5 @@ import { animateTo, stopAnimations } from '../../internal/animate.js'; +import { blurActiveElement } from '../../internal/closeActiveElement.js'; import { classMap } from 'lit/directives/class-map.js'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry.js'; import { HasSlotController } from '../../internal/slot.js'; @@ -157,6 +158,7 @@ export default class SlAlert extends ShoelaceElement { this.emit('sl-after-show'); } else { // Hide + blurActiveElement(this); this.emit('sl-hide'); clearTimeout(this.autoHideTimeout); diff --git a/src/components/dialog/dialog.component.ts b/src/components/dialog/dialog.component.ts index 54f62d02..724b9c0b 100644 --- a/src/components/dialog/dialog.component.ts +++ b/src/components/dialog/dialog.component.ts @@ -1,4 +1,5 @@ import { animateTo, stopAnimations } from '../../internal/animate.js'; +import { blurActiveElement } from '../../internal/closeActiveElement.js'; import { classMap } from 'lit/directives/class-map.js'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry.js'; import { HasSlotController } from '../../internal/slot.js'; @@ -208,6 +209,7 @@ export default class SlDialog extends ShoelaceElement { this.emit('sl-after-show'); } else { // Hide + blurActiveElement(this); this.emit('sl-hide'); this.removeOpenListeners(); this.modal.deactivate(); diff --git a/src/components/drawer/drawer.component.ts b/src/components/drawer/drawer.component.ts index 21d4207f..a1ce0c52 100644 --- a/src/components/drawer/drawer.component.ts +++ b/src/components/drawer/drawer.component.ts @@ -1,4 +1,5 @@ import { animateTo, stopAnimations } from '../../internal/animate.js'; +import { blurActiveElement } from '../../internal/closeActiveElement.js'; import { classMap } from 'lit/directives/class-map.js'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry.js'; import { HasSlotController } from '../../internal/slot.js'; @@ -237,6 +238,7 @@ export default class SlDrawer extends ShoelaceElement { this.emit('sl-after-show'); } else { // Hide + blurActiveElement(this); this.emit('sl-hide'); this.removeOpenListeners(); diff --git a/src/internal/closeActiveElement.ts b/src/internal/closeActiveElement.ts new file mode 100644 index 00000000..0602a0ea --- /dev/null +++ b/src/internal/closeActiveElement.ts @@ -0,0 +1,13 @@ +/** + * Calls the blur method on the current active element if it is a child of the provided element. + * Needed for fixing a11y errors in console. + * @see https://github.com/shoelace-style/shoelace/issues/2283 + * @param elm The element to check + */ +export const blurActiveElement = (elm: HTMLElement) => { + const { activeElement } = document; + console.log(activeElement, elm); + if (activeElement && elm.contains(activeElement)) { + (document.activeElement as HTMLElement)?.blur(); + } +};