Skip to content

Commit bd5e012

Browse files
committed
Improve accessibility, fixes #359
- adds aria-modal="true" to modal portal - doesn't make body a default appElement - warns if appElement is not set in any way
1 parent 700eb4e commit bd5e012

File tree

3 files changed

+22
-39
lines changed

3 files changed

+22
-39
lines changed

specs/Modal.spec.js

-9
Original file line numberDiff line numberDiff line change
@@ -339,15 +339,6 @@ export default () => {
339339
unmountModal();
340340
});
341341

342-
it("uses document.body for aria-hidden if no appElement", () => {
343-
ariaAppHider.documentNotReadyOrSSRTesting();
344-
const node = document.createElement("div");
345-
ReactDOM.render(<Modal isOpen />, node);
346-
document.body.getAttribute("aria-hidden").should.be.eql("true");
347-
ReactDOM.unmountComponentAtNode(node);
348-
should(document.body.getAttribute("aria-hidden")).not.be.ok();
349-
});
350-
351342
it("raises an exception if the appElement selector does not match", () => {
352343
should(() => ariaAppHider.setElement(".test")).throw();
353344
});

src/components/ModalPortal.js

+7-10
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,7 @@ export default class ModalPortal extends Component {
9999
}
100100

101101
componentWillUnmount() {
102-
// Remove body class
103-
bodyClassList.remove(this.props.bodyOpenClassName);
104-
this.beforeClose();
102+
this.afterClose();
105103
clearTimeout(this.closeTimer);
106104
}
107105

@@ -127,17 +125,16 @@ export default class ModalPortal extends Component {
127125
}
128126
}
129127

130-
beforeClose() {
128+
afterClose = () => {
131129
const { appElement, ariaHideApp } = this.props;
130+
131+
// Remove body class
132+
bodyClassList.remove(this.props.bodyOpenClassName);
133+
132134
// Reset aria-hidden attribute if all modals have been removed
133135
if (ariaHideApp && refCount.totalCount() < 1) {
134136
ariaAppHider.show(appElement);
135137
}
136-
}
137-
138-
afterClose = () => {
139-
// Remove body class
140-
bodyClassList.remove(this.props.bodyOpenClassName);
141138

142139
if (this.props.shouldFocusAfterRender) {
143140
if (this.props.shouldReturnFocusAfterClose) {
@@ -171,7 +168,6 @@ export default class ModalPortal extends Component {
171168
};
172169

173170
close = () => {
174-
this.beforeClose();
175171
if (this.props.closeTimeoutMS > 0) {
176172
this.closeWithTimeout();
177173
} else {
@@ -309,6 +305,7 @@ export default class ModalPortal extends Component {
309305
onClick={this.handleOverlayOnClick}
310306
onMouseDown={this.handleOverlayOnMouseDown}
311307
onMouseUp={this.handleOverlayOnMouseUp}
308+
aria-modal="true"
312309
>
313310
<div
314311
ref={this.setContentRef}

src/helpers/ariaAppHider.js

+15-20
Original file line numberDiff line numberDiff line change
@@ -19,42 +19,37 @@ export function setElement(element) {
1919
return globalElement;
2020
}
2121

22-
export function tryForceFallback() {
23-
if (document && document.body) {
24-
// force fallback to document.body
25-
setElement(document.body);
26-
return true;
27-
}
28-
return false;
29-
}
30-
3122
export function validateElement(appElement) {
32-
if (!appElement && !globalElement && !tryForceFallback()) {
33-
throw new Error(
23+
if (!appElement && !globalElement) {
24+
console.warn(
3425
[
35-
"react-modal: Cannot fallback to `document.body`, because it is not",
36-
"ready or available. If you are doing server-side rendering, use this",
37-
"function to defined an element. `Modal.setAppElement(el)` to make",
38-
"this accessible"
26+
"react-modal: App element is not defined.",
27+
"Please use `Modal.setAppElement(el)` or set `appElement` property."
3928
].join(" ")
4029
);
30+
31+
return false;
4132
}
33+
34+
return true;
4235
}
4336

4437
export function hide(appElement) {
45-
validateElement(appElement);
46-
(appElement || globalElement).setAttribute("aria-hidden", "true");
38+
if(validateElement(appElement)) {
39+
(appElement || globalElement).setAttribute("aria-hidden", "true");
40+
}
4741
}
4842

4943
export function show(appElement) {
50-
validateElement(appElement);
51-
(appElement || globalElement).removeAttribute("aria-hidden");
44+
if(validateElement(appElement)) {
45+
(appElement || globalElement).removeAttribute("aria-hidden");
46+
}
5247
}
5348

5449
export function documentNotReadyOrSSRTesting() {
5550
globalElement = null;
5651
}
5752

5853
export function resetForTesting() {
59-
globalElement = document.body;
54+
globalElement = null;
6055
}

0 commit comments

Comments
 (0)