diff --git a/docs/pages/resources/changelog.md b/docs/pages/resources/changelog.md index b3ba3dc3..fdeb59d9 100644 --- a/docs/pages/resources/changelog.md +++ b/docs/pages/resources/changelog.md @@ -18,6 +18,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti - Fixed a bug that in `` that prevented tab from working properly in some cases [#2371] - Fixed the guard on popover to allow virtual elements [#2399] - Fixed the close button in `` so clicking above/below it doesn't inadvertently close it [#2375] +- Fixed accessibility issues for elements that are closed while having slotted focused children. [#2383] ## 2.20.0 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..b87dc515 --- /dev/null +++ b/src/internal/closeActiveElement.ts @@ -0,0 +1,12 @@ +/** + * 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; + if (activeElement && elm.contains(activeElement)) { + (document.activeElement as HTMLElement)?.blur(); + } +};