Skip to content

Commit c80a5d7

Browse files
committed
fix: Properly clean up inert if element is hidden via sub dialog combobox
1 parent f821086 commit c80a5d7

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

packages/@react-aria/overlays/src/ariaHideOutside.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ export function ariaHideOutside(targets: Element[], options?: AriaHideOutsideOpt
5656
element.setAttribute('aria-hidden', 'true');
5757
} else {
5858
element.removeAttribute('aria-hidden');
59+
if (element instanceof windowObj.HTMLElement) {
60+
// We only ever call setHidden with hidden = false when the nodeCount is 1 aka
61+
// we are trying to make the element visible to screen readers again, so remove inert as well
62+
element.inert = false;
63+
}
5964
}
6065
};
6166

packages/@react-aria/overlays/test/ariaHideOutside.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,36 @@ describe('ariaHideOutside', function () {
353353
expect(() => getByRole('button')).not.toThrow();
354354
});
355355

356+
it('should unhide the element even if it was hidden via inert first, then via hideOutside', function () {
357+
let {getByRole} = render(
358+
<>
359+
<input type="radio" />
360+
<button>Button</button>
361+
</>
362+
);
363+
364+
let button = getByRole('button');
365+
let revert1 = ariaHideOutside([button], {shouldUseInert: true});
366+
367+
expect(getByRole('radio', {hidden: true}).inert).toBeTruthy();
368+
expect(() => getByRole('button')).not.toThrow();
369+
370+
let revert2 = ariaHideOutside([button]);
371+
372+
expect(getByRole('radio', {hidden: true}).inert).toBeTruthy();
373+
expect(() => getByRole('button')).not.toThrow();
374+
375+
revert1();
376+
377+
expect(getByRole('radio', {hidden: true}).inert).toBeTruthy();
378+
expect(() => getByRole('button')).not.toThrow();
379+
380+
revert2();
381+
382+
expect(getByRole('radio', {hidden: true}).inert).toBeFalsy();
383+
expect(() => getByRole('button')).not.toThrow();
384+
});
385+
356386
it('should hide everything except the provided element [row]', function () {
357387
let {getAllByRole, getByTestId} = render(
358388
<div role="grid">

scripts/setupTests.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,13 @@ beforeEach(() => {
109109
afterEach(() => {
110110
delete window.IntersectionObserver;
111111
});
112+
113+
Object.defineProperty(HTMLElement.prototype, 'inert', {
114+
configurable: true,
115+
get() {
116+
return this._inert || false;
117+
},
118+
set(value) {
119+
this._inert = value;
120+
}
121+
});

0 commit comments

Comments
 (0)