Skip to content

Commit 67ee9f5

Browse files
committed
[added] allow users to pass aria-* attribute.
This patch allows users to pass custom aria attributes to be added to the modal content. It accepts an object where the keys are the name of the attributes without the prefix aria-*.
1 parent 6f73764 commit 67ee9f5

File tree

7 files changed

+56
-3
lines changed

7 files changed

+56
-3
lines changed

.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"react/no-find-dom-node": [0],
2929
"react/jsx-closing-bracket-location": [0],
3030
"react/jsx-filename-extension": ["error", {"extensions": [".js"]}],
31+
"react/forbid-prop-types": [1, {"forbid": ["any"]}],
3132
"react/require-default-props": 0
3233
}
3334
}

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,28 @@ Modal.setAppElement(appElement);
7676
Modal.setAppElement('#your-app-element');
7777
```
7878

79+
### Additional Aria Attributes
80+
81+
Use the property `aria` to pass any additional aria attributes. It accepts
82+
an object where the keys are the names of the attributes without the prefix
83+
`aria-`.
84+
85+
Example:
86+
87+
```js
88+
<Modal
89+
isOpen={modalIsOpen}
90+
aria={{
91+
labelledby: "heading",
92+
describedby: "full_description"
93+
}}>
94+
<h1 id="heading">H1</h1>
95+
<div id="full_description">
96+
<p>Description goes here.</p>
97+
</div>
98+
</Modal>
99+
```
100+
79101
## Styles
80102

81103
Styles are passed as an object with 2 keys, 'overlay' and 'content' like so

docs/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ import ReactModal from 'react-modal';
8282
Function that will be called to get the parent element that the modal will be attached to.
8383
*/
8484
parentSelector={() => document.body}
85+
/*
86+
Additional aria attributes (optional).
87+
*/
88+
aria={{
89+
labelledby: "heading",
90+
describedby: "full_description"
91+
}}
8592
/>
8693
```
8794

examples/basic/app.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,19 @@ class App extends Component {
6969
</Modal>
7070
<Modal ref="mymodal2"
7171
id="test2"
72+
aria={{
73+
labelledby: "heading",
74+
describedby: "fulldescription"
75+
}}
7276
closeTimeoutMS={150}
7377
contentLabel="modalB"
7478
isOpen={modal2}
7579
onAfterOpen={() => {}}
7680
onRequestClose={this.toggleModal_2}>
77-
<p>test</p>
81+
<h1 id="heading">This is the modal 2!</h1>
82+
<div id="fulldescription" tabIndex="0" role="document">
83+
<p>This is a description of what it does: nothing :)</p>
84+
</div>
7885
</Modal>
7986
</div>
8087
);

specs/Modal.spec.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ describe('State', () => {
239239
unmountModal();
240240
expect(!isBodyWithReactModalOpenClass()).toBeTruthy();
241241
});
242-
242+
243243
it('should not add classes to document.body for unopened modals', () => {
244244
renderModal({ isOpen: true });
245245
expect(isBodyWithReactModalOpenClass()).toBeTruthy();
@@ -259,6 +259,14 @@ describe('State', () => {
259259
expect(isBodyWithReactModalOpenClass()).toBeTruthy();
260260
});
261261

262+
it('additional aria attributes', () => {
263+
const modal = renderModal({ isOpen: true, aria: { labelledby: "a" }}, 'hello');
264+
expect(
265+
mcontent(modal).getAttribute('aria-labelledby')
266+
).toEqual("a");
267+
unmountModal();
268+
});
269+
262270
it('adding/removing aria-hidden without an appElement will try to fallback to document.body', () => {
263271
ariaAppHider.documentNotReadyOrSSRTesting();
264272
const node = document.createElement('div');

src/components/Modal.js

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export default class Modal extends Component {
5353
ariaHideApp: PropTypes.bool,
5454
shouldCloseOnOverlayClick: PropTypes.bool,
5555
parentSelector: PropTypes.func,
56+
aria: PropTypes.object,
5657
role: PropTypes.string,
5758
contentLabel: PropTypes.string.isRequired
5859
};

src/components/ModalPortal.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default class ModalPortal extends Component {
5151
shouldCloseOnOverlayClick: PropTypes.bool,
5252
role: PropTypes.string,
5353
contentLabel: PropTypes.string,
54+
aria: PropTypes.object,
5455
children: PropTypes.node
5556
};
5657

@@ -254,6 +255,11 @@ export default class ModalPortal extends Component {
254255
`${className} ${additional}` : className;
255256
}
256257

258+
ariaAttributes = items => Object.keys(items).reduce((acc, name) => {
259+
acc[`aria-${name}`] = items[name];
260+
return acc;
261+
}, {});
262+
257263
render() {
258264
const { className, overlayClassName, defaultStyles } = this.props;
259265
const contentStyles = className ? {} : defaultStyles.content;
@@ -273,7 +279,8 @@ export default class ModalPortal extends Component {
273279
onKeyDown={this.handleKeyDown}
274280
onClick={this.handleContentOnClick}
275281
role={this.props.role}
276-
aria-label={this.props.contentLabel}>
282+
aria-label={this.props.contentLabel}
283+
{...this.ariaAttributes(this.props.aria || {})}>
277284
{this.props.children}
278285
</div>
279286
</div>

0 commit comments

Comments
 (0)