floating-ui

Floating UI - is it possible to avoid the popper being clipped by overflow:hidden on the parent?


I'm trying to create a dropdown element with floating-ui. My problem is that when the floating ui element is within a parent that has overflow: hidden/auto/scroll then the floating element is hidden/clipped by that overflow setting. I'd like the floating element, in this instance, to be attached outside of this DOM structure, so that it's not affected by the overflow setting. Material UI (mat-select) does this.

I have the code below, and I would expect that the detectOverflow middleware to be attaching my floating-ui element to the body, but it doesn't.

        computePosition(triggerElement, popperElement, {
            placement: 'bottom',
            middleware: [
                flip(),
                {
                    name: 'middleware',
                    async fn(state) {
                        const overflow = await detectOverflow(state, {
                            boundary: document.querySelector('body')
                        });
                        return {};
                    }
                }
            ]
        }).then(({ x, y }) => {
            Object.assign(optionsElement.style, {
                left: `${x}px`,
                top: `${y}px`
            });
        });

Solution

  • With a ping to their github site, I was given back the following code which does return what I want and can then use it:

    const middlewareDO = {
      name: "mything",
      async fn(state) {
        const overflow = await detectOverflow(state, {
          boundary: body,
        });
        return {
          data: {
            shouldFlip: overflow.top >= 0,
          }
        };
      },
    };
    

    Note the data: portion, that was not in the docs and still is not.

    In my case, body is an element I want it to clip on, not the actual page body.

    You can then access it via the middlewareData.mything.shouldFlip when you pass the other 2 parameters to it, placement, middlewareData:

    .then(({ x, y, placement, middlewareData }) => {
      Object.assign(popover.style, {
        left: `${x}px`,
        top: `${y}px`,
      });
    
      const { x: arrowX, y: arrowY } = middlewareData.arrow;
      ...
    }