'Open only one React-Bootstrap Popover at a time

I'm using React-Bootstrap Popover and I was wondering if there is any builtin property that I can add either to Popover itself or to OverlayTrigger so only one popover will display at a time.



Solution 1:[1]

You can try rootClose props which will trigger onHide when the user clicks outside the overlay. Please note that in this case onHide is mandatory. e.g:

const Example = React.createClass({
  getInitialState() {
    return { show: true };
  },

  toggle() {
    this.setState({ show: !this.state.show });
  },

  render() {
    return (
      <div style={{ height: 100, position: 'relative' }}>
        <Button ref="target" onClick={this.toggle}>
          I am an Overlay target
        </Button>

        <Overlay
          show={this.state.show}
          onHide={() => this.setState({ show: false })}
          placement="right"
          container={this}
          target={() => ReactDOM.findDOMNode(this.refs.target)}
          rootClose
        >
          <CustomPopover />
        </Overlay>
      </div>
    );
  },
});

Solution 2:[2]

I managed to do this in a somewhat unconventional manner. You can create a class which tracks the handlers of all of your tooltips:

export class ToolTipController {
  showHandlers = [];
  addShowHandler = (handler) => {
    this.showHandlers.push(handler);
  };
  setShowHandlerTrue = (handler) => {
    this.showHandlers.forEach((showHandler) => {
      if (showHandler !== handler) {
        showHandler(false);
      }
    });
    handler(true);
  };
}

Then in your tooltip component:

const CustomToolTip = ({
  children,
  controller,
}: CustomToolTipProps) => {
  const [showTip, setShowTip] = useState(false);

  useEffect(() => {
    if (!controller) return;
    controller.addShowHandler(setShowTip);
  }, []);

  return (
    <OverlayTrigger
      onToggle={(nextShow) => {
        if (!nextShow) return setShowTip(false);
        controller ? controller.setShowHandlerTrue(setShowTip) : setShowTip(true);
      }}
      show={showTip}
      overlay={(props: any) => <Overlay {...props}/>}
    >
      <div className={containerClassName}>{children}</div>
    </OverlayTrigger>
  );
};

It's not really a 'Reacty' solution but it works quite nicely. Note that the controller is completely optional here so if you wanted you could not pass that in and it would then behave like a normal popover allowing multiple tooltips at once.

Basically to use it you can create another component and instantiate a controller which you pass into CustomToolTip. Then for any tooltips which are rendered using that component, only 1 will appear at a time.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 DannyMoshe