|
54 | 54 | }" |
55 | 55 | :role="role" |
56 | 56 | :data-qa="$attrs['data-qa'] ? `${$attrs['data-qa']}__dialog` : 'dt-popover'" |
57 | | - :aria-hidden="`${!isOpen}`" |
| 57 | + :aria-hidden="`${isDialogAriaHidden}`" |
58 | 58 | :aria-labelledby="labelledBy" |
59 | 59 | :aria-label="ariaLabel" |
60 | 60 | :aria-modal="`${!modal}`" |
@@ -640,6 +640,9 @@ export default { |
640 | 640 | mutationObserver: null, |
641 | 641 | isOutsideViewport: false, |
642 | 642 | isOpen: false, |
| 643 | + // Only true once the leave transition (and any focus restoration in onLeaveTransitionComplete) has |
| 644 | + // finished, so aria-hidden is never applied while the dialog still holds focus or is still visible. |
| 645 | + isDialogAriaHidden: true, |
643 | 646 | toAppear: false, |
644 | 647 | anchorEl: null, |
645 | 648 | popoverContentEl: null, |
@@ -754,6 +757,7 @@ export default { |
754 | 757 |
|
755 | 758 | isOpen (isOpen, isPrev) { |
756 | 759 | if (isOpen) { |
| 760 | + this.isDialogAriaHidden = false; |
757 | 761 | this.initTippyInstance(); |
758 | 762 | this.tip?.show(); |
759 | 763 | } else if (!isOpen && isPrev !== isOpen) { |
@@ -995,6 +999,9 @@ export default { |
995 | 999 | this.enableScrolling(); |
996 | 1000 | } |
997 | 1001 | if (this._isUnmounting) return; |
| 1002 | + // Focus has been moved off the dialog (or was never trapped in it) by this point, so it's now |
| 1003 | + // safe to hide it from assistive technology without triggering a focused-descendant violation. |
| 1004 | + this.isDialogAriaHidden = true; |
998 | 1005 | this.tip?.unmount(); |
999 | 1006 | this.$emit('opened', false); |
1000 | 1007 | if (this.open !== null) { |
|
0 commit comments