Skip to content

Commit 97ef415

Browse files
committedJun 29, 2015
[fixed] Modal won't steal focus from children
fixes react-bootstrap#903
1 parent a8b177a commit 97ef415

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed
 

‎src/Modal.js

+22-3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ const Modal = React.createClass({
101101
animation: React.PropTypes.bool,
102102
onRequestHide: React.PropTypes.func.isRequired,
103103
dialogClassName: React.PropTypes.string,
104+
autoFocus: React.PropTypes.bool,
104105
enforceFocus: React.PropTypes.bool
105106
},
106107

@@ -111,6 +112,8 @@ const Modal = React.createClass({
111112
keyboard: true,
112113
animation: true,
113114
closeButton: true,
115+
116+
autoFocus: true,
114117
enforceFocus: true
115118
};
116119
},
@@ -205,6 +208,10 @@ const Modal = React.createClass({
205208
React.findDOMNode(this.refs.backdrop).onclick = function () {};
206209
},
207210

211+
componentWillMount(){
212+
this.checkForFocus();
213+
},
214+
208215
componentDidMount() {
209216
const doc = domUtils.ownerDocument(this);
210217
const win = domUtils.ownerWindow(this);
@@ -286,11 +293,23 @@ const Modal = React.createClass({
286293
this.setState(this._getStyles());
287294
},
288295

296+
checkForFocus(){
297+
if ( domUtils.canUseDom ) {
298+
try {
299+
this.lastFocus = document.activeElement;
300+
}
301+
catch (e) {}
302+
}
303+
},
304+
289305
focusModalContent () {
290-
if (this.props.enforceFocus) {
291-
this.lastFocus = domUtils.activeElement(this);
306+
let modalContent = React.findDOMNode(this.refs.modal);
307+
let current = domUtils.activeElement(this);
308+
let focusInModal = current && domUtils.contains(modalContent, current);
309+
310+
if (this.props.autoFocus && !focusInModal) {
311+
this.lastFocus = current;
292312

293-
let modalContent = React.findDOMNode(this.refs.modal);
294313
modalContent.focus();
295314
}
296315
},

‎test/ModalSpec.js

+34-2
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ describe('Modal', function () {
156156
}, 0);
157157
});
158158

159-
it('Should not focus on the Modal when enforceFocus is false', function (done) {
159+
it('Should not focus on the Modal when autoFocus is false', function (done) {
160160

161161
document.activeElement.should.equal(focusableContainer);
162162

@@ -167,7 +167,7 @@ describe('Modal', function () {
167167
render() {
168168
if (this.state.modalOpen) {
169169
return (
170-
<Modal enforceFocus={false} onRequestHide={()=>{}} container={this}>
170+
<Modal autoFocus={false} onRequestHide={()=>{}} container={this}>
171171
<strong>Message</strong>
172172
</Modal>
173173
);
@@ -185,6 +185,38 @@ describe('Modal', function () {
185185
done();
186186
}, 0);
187187
});
188+
189+
it('Should not focus Modal when child has focus', function (done) {
190+
191+
document.activeElement.should.equal(focusableContainer);
192+
193+
let Container = React.createClass({
194+
getInitialState() {
195+
return {modalOpen: true};
196+
},
197+
render() {
198+
if (this.state.modalOpen) {
199+
return (
200+
<Modal onRequestHide={()=>{}} container={this}>
201+
<input autoFocus />
202+
</Modal>
203+
);
204+
} else {
205+
return <span/>;
206+
}
207+
}
208+
});
209+
210+
var instance = React.render(<Container />, focusableContainer);
211+
212+
setTimeout(function () {
213+
let input = React.findDOMNode(
214+
ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'input'))
215+
216+
document.activeElement.should.equal(input);
217+
done();
218+
}, 0);
219+
});
188220
});
189221

190222

0 commit comments

Comments
 (0)
Please sign in to comment.