floating-ui / react-popper

🍿⚛Official React library to use Popper, the positioning library
https://popper.js.org/react-popper/
MIT License
2.5k stars 226 forks source link

How to size popper dynamically with detectOverflow #452

Open mhanley00 opened 1 year ago

mhanley00 commented 1 year ago

Reproduction demo

Steps to reproduce the problem

  1. Create a popper with no outside CSS (other than the attribute positioning)
  2. Create a memoized detectOverflow modifier that attempts to modify the size of the popper if overflow is detected (ie if right/left/top/bottom > 0):
const preventOverflow = React.useMemo(
    () => ({
      name: 'detectOverflow',
      enabled: true,
      phase: 'main',
      requiresIfExists: ['offset'],
      fn: (data) => {

        const overflow = detectOverflow(data.state);
        /*If the number is positive, the popper is overflowing by that number of pixels.
        When 0, or negative, the popper is within its boundaries. */
        if (
          overflow.right >= 0 ||
          overflow.left >= 0 ||
          overflow.top >= 0 ||
          overflow.bottom >= 0
        ) {
          const width = 220;
          const height = 200;
         /* Manually update the popper object*/
          const popper = {
            ...data.state.rects,
            popper: { ...data.state.rects.popper, width, height },
          };

          const state = { ...data.state, rects: popper };

          return { ...data, state, instance: { ...data.instance, state } };
        }
      },
    }),
    [],
  );

What is the expected behavior?

Based on this response: https://github.com/floating-ui/react-popper/issues/73 I would expect to be able to manually update the size of the popper when overflow is detected.

What went wrong?

I'm unsuccessful in trying to update the height and width of the popper based on available screen size. Previously I had done this outside of the modifier in a useEffect based on screen size, but because we don't always have the popper attributes available (ie position, sometimes they're null when it hasn't initialized yet) to know how much available space we actually have, then we have to make it smaller based on width so we can eventually fit the popper over top of the anchor, when there's really plenty of space, say, to the left.

Any other comments?

Please let me know if you need anything else from me! Thank you so much for making this Popper.js free, it's one of my all-time favorites libs.

Packages versions

FezVrasta commented 1 year ago

Did you try the https://www.npmjs.com/package/popper-max-size-modifier package?

atomiks commented 1 year ago

I deprecated that and pointed to https://floating-ui.com/docs/size as it was buggy in a couple ways — I recommend just switching to Floating UI as it's getting full support and the size modifier is much more reliable and easier to use

mhanley00 commented 1 year ago

Thank you both so much for your help! @atomiks awesome, Floating-UI looks like the way to go 💯