react-bootstrap: React bootstrap OverlayTrigger Popover changes its placement when opening and closing

Prerequisites

Describe the bug

I have a Popover that is wrapped in forwardRef and when i open/close it, its placement changes. Also on mobile resolution the Popover appears outside the parent element.

Expected behavior

I need the Popover to always be in the parent element and not outside of it.

To Reproduce

  1. Open sandbox (if you get root stylesheet error, refresh sandbox)
  2. Click on details button on any character
  3. Try open any popover

Reproducible Example

Sandbox - link

Screenshots

popover

What operating system(s) are you seeing the problem on?

Windows

What browser(s) are you seeing the problem on?

Chrome

What version of React-Bootstrap are you using?

2.3.0

What version of Bootstrap are you using?

5.1.3

Additional context

OverlayTrigger - src/components/DetailModal

               <div className="detail-modal__item__value episodes">
                {details.episode.map((ep: string) => {
                  return (
                    <OverlayTrigger
                      trigger="click"
                      placement="auto"
                      overlay={<EpisodePopover url={ep} />}
                      container={modalRef}
                      key={ep}
                    >
                      <p>{ep.split("episode/")[1]}</p>
                    </OverlayTrigger>
                  );
                })}
              </div>

Popover - src/components/Popovers/EpisodePopover

const EpisodePopover = React.forwardRef<HTMLDivElement, IPopoverProps>((props, ref) => {
    const { url } = props;
    const [episode, setEpisode] = React.useState<IEpisode>(null);
    const [isLoading, setLoading] = React.useState<boolean>(true);

    React.useEffect(() => {
      axios
        .get(url)
        .then(({ data }) => {
          setEpisode(data);
        })
        .catch((error) => {
          console.error("EpisodePopover", error);
        })
        .finally(() => {
          setLoading(false);
        });
    }, []); // eslint-disable-line

    return (
      <Popover className="popover" id="popover-basic" ref={ref} {...props}>
        <Popover.Body>
          {isLoading ? (
            <Loader />
          ) : (
            <>
              <div className="popover__item">
                <p className="popover__item__title">Name:</p>
                <p className="popover__item__value">{episode.name}</p>
              </div>
              <div className="popover__item">
                <p className="popover__item__title">Episode:</p>
                <p className="popover__item__value">{episode.episode}</p>
              </div>
              <div className="popover__item">
                <p className="popover__item__title">Air date:</p>
                <p className="popover__item__value">{episode.air_date}</p>
              </div>
            </>
          )}
        </Popover.Body>
      </Popover>
    );
  }
);

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 18 (2 by maintainers)

Most upvoted comments

For anyone coming in from Google.

This can occur if you forget to send props to the tooltip from the overlay.

So, for example:

export type SimpleTooltipProps = {
    title?: string | null;
    children: React.ReactElement | ((props: OverlayTriggerRenderProps) => React.ReactNode);
}

export function SimpleTooltip({ title, children }: SimpleTooltipProps) {
    let id = useMemo(() => uuid.v4(), []);
    return title
        ? (
            <OverlayTrigger overlay={props => <Tooltip id={id} {...props}>{title}</Tooltip>}>
                {children}
            </OverlayTrigger>
        )
        : <>{children}</>
}

Reading the docs also tells you this, the failure mode just doesn’t make this obvious.

Demo with 2.5.0-beta.1 https://codesandbox.io/s/aged-wood-wkvkgx?file=/src/App.js

It’s positioned but with flicker Component from examples

@artygrand I fixed it by add position: absolute to Tooltip https://codesandbox.io/s/pedantic-sky-7ge7t1?file=/src/App.js

Demo with 2.5.0-beta.1 https://codesandbox.io/s/aged-wood-wkvkgx?file=/src/App.js

It’s positioned but with flicker Component from examples

@isherwood can you try this with 2.5.0-beta.0?