diff --git a/CHANGELOG.md b/CHANGELOG.md
index b2bc4f10e4d..de32fefe811 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
- Added `spacesApp` logo to `EuiIcon` set ([#1065](https://github.com/elastic/eui/pull/1065))
- Added `!default` to border SASS props ([#1079](https://github.com/elastic/eui/pull/1079))
+- Added `repositionOnScroll` prop to `EuiPopover` which enables repositioning the popover when the window is scrolled. ([#1064](https://github.com/elastic/eui/pull/1064))
**Bug fixes**
diff --git a/src-docs/src/views/popover/popover_example.js b/src-docs/src/views/popover/popover_example.js
index 4b86b9d15ed..ac41ed3dedb 100644
--- a/src-docs/src/views/popover/popover_example.js
+++ b/src-docs/src/views/popover/popover_example.js
@@ -44,6 +44,9 @@ import PopoverContainer from './popover_container';
const popoverContainerSource = require('!!raw-loader!./popover_container');
const popoverContainerHtml = renderToHtml(PopoverContainer);
+import PopoverFixed from './popover_fixed';
+const popoverFixedSource = require('!!raw-loader!./popover_fixed');
+const popoverFixedHtml = renderToHtml(PopoverFixed);
export const PopoverExample = {
title: 'Popover',
@@ -204,5 +207,22 @@ export const PopoverExample = {
),
demo: ,
+ }, {
+ title: 'Popover on a fixed element',
+ source: [{
+ type: GuideSectionTypes.JS,
+ code: popoverFixedSource,
+ }, {
+ type: GuideSectionTypes.HTML,
+ code: popoverFixedHtml,
+ }],
+ text: (
+
+
+ Popover content even works on position: fixed; elements.
+
+
+ ),
+ demo: ,
}],
};
diff --git a/src-docs/src/views/popover/popover_fixed.js b/src-docs/src/views/popover/popover_fixed.js
new file mode 100644
index 00000000000..f543a513353
--- /dev/null
+++ b/src-docs/src/views/popover/popover_fixed.js
@@ -0,0 +1,67 @@
+import React, {
+ Component,
+} from 'react';
+
+import {
+ EuiButton,
+ EuiPopover,
+} from '../../../../src/components';
+
+export default class PopoverContainer extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ isExampleShown: false,
+ isPopoverOpen: false,
+ };
+ }
+
+ toggleExample = () => this.setState(({ isExampleShown }) => ({ isExampleShown: !isExampleShown }))
+
+ onButtonClick = () => {
+ this.setState({
+ isPopoverOpen: !this.state.isPopoverOpen,
+ });
+ }
+
+ closePopover = () => {
+ this.setState({
+ isPopoverOpen: false,
+ });
+ }
+
+ setPanelRef = node => this.panel = node;
+
+ render() {
+ const button = (
+
+ Show fixed popover
+
+ );
+
+ return (
+
+ Toggle Example
+ {this.state.isExampleShown && (
+
+
+ This popover scrolls with the button element!
+
+
+ )}
+
+ );
+ }
+}
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index 719b1013b73..8a0db98038c 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -153,6 +153,10 @@ export class EuiPopover extends Component {
this.setState({ suppressingPopover: false, isOpening: true }); // eslint-disable-line react/no-did-mount-set-state
}
+ if (this.props.repositionOnScroll) {
+ window.addEventListener('scroll', this.positionPopover);
+ }
+
this.updateFocus();
}
@@ -169,6 +173,15 @@ export class EuiPopover extends Component {
});
}
+ // update scroll listener
+ if (prevProps.repositionOnScroll !== this.props.repositionOnScroll) {
+ if (this.props.repositionOnScroll) {
+ window.addEventListener('scroll', this.positionPopover);
+ } else {
+ window.removeEventListener('scroll', this.positionPopover);
+ }
+ }
+
// The popover is being closed.
if (prevProps.isOpen && !this.props.isOpen) {
// If the user has just closed the popover, queue up the removal of the content after the
@@ -184,6 +197,7 @@ export class EuiPopover extends Component {
}
componentWillUnmount() {
+ window.removeEventListener('scroll', this.positionPopover);
clearTimeout(this.closingTransitionTimeout);
}
@@ -420,6 +434,8 @@ EuiPopover.propTypes = {
PropTypes.node,
PropTypes.instanceOf(HTMLElement)
]),
+ /** When `true`, the popover's position is re-calculated when the user scrolls, this supports having fixed-position popover anchors. */
+ repositionOnScroll: PropTypes.bool,
};
EuiPopover.defaultProps = {