diff --git a/react/package.json b/react/package.json
index 0836483b47..5a5918c59e 100644
--- a/react/package.json
+++ b/react/package.json
@@ -78,6 +78,7 @@
"object-assign": "4.1.1",
"react-aria-modal": "^2.11.1",
"react-context-toolbox": "^2.0.2",
+ "react-focus-lock": "^1.19.1",
"react-uid": "^2.2.0"
},
"devDependencies": {
diff --git a/react/src/lib/EventOverlay/index.js b/react/src/lib/EventOverlay/index.js
index fc9e396c9d..a2ab567787 100644
--- a/react/src/lib/EventOverlay/index.js
+++ b/react/src/lib/EventOverlay/index.js
@@ -4,6 +4,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import omit from 'lodash/omit';
+import FocusLock from 'react-focus-lock';
const defaultDims = {
offsetTop: 0,
@@ -837,10 +838,12 @@ class EventOverlay extends React.Component {
const {
children,
className,
+ focusLockProps,
isOpen,
maxHeight,
maxWidth,
portalNode,
+ shouldLockFocus,
showArrow,
style,
...props
@@ -866,7 +869,7 @@ class EventOverlay extends React.Component {
const contentNodes = (
isOpen && (
(
+ shouldLockFocus
+ ? {content}
+ : content
+ );
+
+ const withPortal = content => (
+ portalNode
+ ? ReactDOM.createPortal(
+ content,
+ portalNode
+ )
+ : content
+ );
+
+ return withFocusLock(
+ withPortal(contentNodes)
+ );
}
}
@@ -915,6 +930,7 @@ EventOverlay.defaultProps = {
className: '',
close: null,
direction: 'bottom-left',
+ focusLockProps: null,
isContained: '',
isDynamic: false,
isOpen: false,
@@ -922,6 +938,7 @@ EventOverlay.defaultProps = {
maxWidth: null,
portalNode: null,
scrollParentID: null,
+ shouldLockFocus: false,
showArrow: false,
style: null,
targetOffset: {
@@ -965,6 +982,8 @@ EventOverlay.propTypes = {
'right-top',
'right-bottom'
]),
+ /** @prop Props to be passed to focus lock component | null */
+ focusLockProps: PropTypes.object,
/** @prop Determines if the overlay is contained in bounding ancestor | '' */
isContained: PropTypes.oneOf([ true, false, 'horizontal', 'vertical', 'both', '']),
/** @prop When true, will flip children based on space available (does not work with isContained) | false */
@@ -979,6 +998,8 @@ EventOverlay.propTypes = {
portalNode: PropTypes.oneOfType([ PropTypes.node, PropTypes.instanceOf(Element) ]),
/** @prop Set the id of the scrollParent | null */
scrollParentID: PropTypes.string,
+ /** @prop Determines if focus should be locked to overlay | false */
+ shouldLockFocus: PropTypes.bool,
/** @prop Determines if the EventOverlay should show the open/close arrow | false */
showArrow: PropTypes.bool,
/** @prop Optional css styling | null */
diff --git a/react/src/lib/EventOverlay/tests/__snapshots__/index.spec.js.snap b/react/src/lib/EventOverlay/tests/__snapshots__/index.spec.js.snap
index f0c0652814..aab1040a15 100644
--- a/react/src/lib/EventOverlay/tests/__snapshots__/index.spec.js.snap
+++ b/react/src/lib/EventOverlay/tests/__snapshots__/index.spec.js.snap
@@ -12,6 +12,7 @@ ShallowWrapper {
className=""
close={null}
direction="bottom-left"
+ focusLockProps={null}
isContained=""
isDynamic={false}
isOpen={false}
@@ -19,6 +20,7 @@ ShallowWrapper {
maxWidth={null}
portalNode={null}
scrollParentID={null}
+ shouldLockFocus={false}
showArrow={false}
style={null}
targetOffset={