From 5313abe35b26e10240a2cc3d55d8c68d16f89c14 Mon Sep 17 00:00:00 2001 From: Joao Portela Date: Sun, 17 May 2015 18:42:39 +0100 Subject: [PATCH] [fixed] Modal is focused when opened, for improved accessibility Adds test case for focusing on the modal when opening it --- src/Modal.js | 17 +++++++++++++ test/ModalSpec.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/Modal.js b/src/Modal.js index 3989cb68f5..1281304fb4 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -126,6 +126,8 @@ const Modal = React.createClass({ domUtils.ownerDocument(this).body; container.className += container.className.length ? ' modal-open' : 'modal-open'; + this.focusModalContent(); + if (this.props.backdrop) { this.iosClickHack(); } @@ -142,6 +144,8 @@ const Modal = React.createClass({ let container = (this.props.container && React.findDOMNode(this.props.container)) || domUtils.ownerDocument(this).body; container.className = container.className.replace(/ ?modal-open/, ''); + + this.restoreLastFocus(); }, handleBackdropClick(e) { @@ -156,6 +160,19 @@ const Modal = React.createClass({ if (this.props.keyboard && e.keyCode === 27) { this.props.onRequestHide(); } + }, + + focusModalContent () { + this.lastFocus = document.activeElement; + let modalContent = React.findDOMNode(this.refs.modal); + modalContent.focus(); + }, + + restoreLastFocus () { + if (this.lastFocus) { + this.lastFocus.focus(); + this.lastFocus = null; + } } }); diff --git a/test/ModalSpec.js b/test/ModalSpec.js index eeafc6d004..c4ee1d38ff 100644 --- a/test/ModalSpec.js +++ b/test/ModalSpec.js @@ -97,4 +97,65 @@ describe('Modal', function () { assert.match(dialog.props.className, /\btestCss\b/); }); + describe('Focused state', function () { + let focusableContainer = null; + beforeEach(function () { + focusableContainer = document.createElement('div'); + focusableContainer.tabIndex = 0; + document.body.appendChild(focusableContainer); + focusableContainer.focus(); + }); + + afterEach(function () { + React.unmountComponentAtNode(focusableContainer); + document.body.removeChild(focusableContainer); + }); + + it('Should focus on the Modal when it is opened', function (done) { + document.activeElement.should.equal(focusableContainer); + + let doneOp = function () { + // focus should be back on the previous element when modal closed + setTimeout(function () { + document.activeElement.should.equal(focusableContainer); + done(); + }, 0); + }; + + let Container = React.createClass({ + getInitialState() { + return {modalOpen: true}; + }, + handleCloseModal() { + this.setState({modalOpen: false}); + doneOp(); + }, + render() { + if (this.state.modalOpen) { + return ( + + Message + + ); + } else { + return ; + } + } + }); + + let instance = React.render(, focusableContainer); + + setTimeout(function () { + // modal should be focused when opened + let modal = instance.getDOMNode().getElementsByClassName('modal')[0]; + document.activeElement.should.equal(modal); + + // close the modal + let backdrop = instance.getDOMNode().getElementsByClassName('modal-backdrop')[0]; + ReactTestUtils.Simulate.click(backdrop); + }, 0); + }); + + }); + });