Skip to content

Commit de14816

Browse files
jshthorntonclaydiffrient
authored andcommitted
[added] Ability for modal to be appended to arbitrary elements (#183)
* The ability to specify the parent via a selector * Using object to denote dom element * allow only function as parentSelector * update README * Fix parent selector type and default value
1 parent 3fdc672 commit de14816

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

README.md

+20
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ This doesn't affect styling as no styles are applied to this element by default.
7373
The default styles above are available on `Modal.defaultStyles`. Changes to this
7474
object will apply to all instances of the modal.
7575

76+
### Appended to custom node
77+
You can choose an element for the modal to be appended to, rather than using
78+
body tag. To do this, provide a function to `parentSelector` prop that return
79+
the element to be used.
80+
81+
```jsx
82+
83+
function getParent() {
84+
return document.querySelector('#root');
85+
}
86+
87+
<Modal
88+
...
89+
parentSelector={getParent}
90+
...
91+
>
92+
<p>Modal Content.</p>
93+
</Modal>
94+
```
95+
7696
### Body class
7797
When the modal is opened a `ReactModal__Body--open` class is added to the `body` tag.
7898
You can use this to remove scrolling on the the body while the modal is open.

lib/components/Modal.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ var Assign = require('lodash.assign');
1010
var SafeHTMLElement = ExecutionEnvironment.canUseDOM ? window.HTMLElement : {};
1111
var AppElement = ExecutionEnvironment.canUseDOM ? document.body : {appendChild: function() {}};
1212

13+
function getParentElement(parentSelector) {
14+
return parentSelector();
15+
}
16+
1317
var Modal = React.createClass({
1418

1519
displayName: 'Modal',
@@ -37,6 +41,7 @@ var Modal = React.createClass({
3741
closeTimeoutMS: React.PropTypes.number,
3842
ariaHideApp: React.PropTypes.bool,
3943
shouldCloseOnOverlayClick: React.PropTypes.bool,
44+
parentSelector: React.PropTypes.func,
4045
role: React.PropTypes.string,
4146
contentLabel: React.PropTypes.string.isRequired
4247
},
@@ -47,18 +52,29 @@ var Modal = React.createClass({
4752
portalClassName: 'ReactModalPortal',
4853
ariaHideApp: true,
4954
closeTimeoutMS: 0,
50-
shouldCloseOnOverlayClick: true
55+
shouldCloseOnOverlayClick: true,
56+
parentSelector: () => document.body
5157
};
5258
},
5359

5460
componentDidMount: function() {
5561
this.node = document.createElement('div');
5662
this.node.className = this.props.portalClassName;
57-
document.body.appendChild(this.node);
63+
64+
var parent = getParentElement(this.props.parentSelector);
65+
parent.appendChild(this.node);
5866
this.renderPortal(this.props);
5967
},
6068

6169
componentWillReceiveProps: function(newProps) {
70+
var currentParent = getParentElement(this.props.parentSelector);
71+
var newParent = getParentElement(newProps.parentSelector);
72+
73+
if(newParent !== currentParent) {
74+
currentParent.removeChild(this.node);
75+
newParent.appendChild(this.node);
76+
}
77+
6278
this.renderPortal(newProps);
6379
},
6480

@@ -68,7 +84,8 @@ var Modal = React.createClass({
6884
}
6985

7086
ReactDOM.unmountComponentAtNode(this.node);
71-
document.body.removeChild(this.node);
87+
var parent = getParentElement(this.props.parentSelector);
88+
parent.removeChild(this.node);
7289
elementClass(document.body).remove('ReactModal__Body--open');
7390
},
7491

0 commit comments

Comments
 (0)