floating-ui icon indicating copy to clipboard operation
floating-ui copied to clipboard

isPositioned only becomes true after setting the open option to false

Open sebbayer opened this issue 1 year ago • 2 comments

Describe the bug Looking at the documentation of Vue Effects I understand that positioning is done in an async function and that the useFloating composable returns an isPositioned boolean ref that lets me know if the floating element has been positioned. I can also provide an open option that represents the open/close state of the floating element. So far, so good.

Judging from the linked example in the documentation, I would expect that the isPositioned ref would be set to true everytime the floating element has been opened, so I can for example focus elements inside it. I need to ensure the positioning is done first before focusing anything to prevent unwanted scrolling behaviour. But isPositioned only becomes true after the open option has been set to false. See my example. This way, I can never determine when the positioning is done after opening a dropdown.

The linked documentation says in the comment:

Each time the floating element opens, we want to focus and scroll some element into view.

So either I am using isPositioned wrong or the library is not working as intended per the documentation.

To Reproduce

I forked the @floating-ui/vue demo: https://codesandbox.io/p/sandbox/floating-ui-vue-demo-forked-wrzxdx

Steps to reproduce the behavior:

  1. Open the codesandbox link
  2. Click on the button multiple times
  3. See how isPositioned only becomes true after open is set to false.

Expected behavior I would expect isPositioned to be set every time the open option updates, not only when it is false.

Context:

  • OS: macOS Sonoma
  • Browser Chrome 127
  • Version @floating-ui/vue 1.1.3

sebbayer avatar Aug 21 '24 17:08 sebbayer

Seems like the sandbox is private: image

oleksandr-danylchenko avatar Aug 26 '24 10:08 oleksandr-danylchenko

Sorry @oleksandr-danylchenko, it should be accessible now.

sebbayer avatar Aug 26 '24 10:08 sebbayer

@lozinsky can you take a look here?

atomiks avatar Sep 04 '24 00:09 atomiks

The issue also applies to the @floating-ui/react package, because useFloating from @floating-ui/vue implements the same behaviour.

Demo: https://codesandbox.io/p/sandbox/floating-ui-react-demo-p5rxyp

This happens because you hide your floating element via CSS. Changing the value of isOpen changes the geometry of the element, which causes autoUpdate and recalculates the position. The documentation recommends to avoid the whileElementsMounted usage without conditional rendering:

Ensure you are using conditional rendering (v-if) for the floating element, not an opacity/visibility/display style. If you are using v-show instead, avoid the whileElementsMounted prop.

Eventually isPositioned became true after setting isOpen to false, because the element is positioned via autoUpdate.

lozinsky avatar Sep 04 '24 11:09 lozinsky

@lozinsky thanks for the explanation and the react demo. I forked my Vue example again, removed the whileElementsMounted property (and updated to v-show). https://codesandbox.io/p/sandbox/floating-ui-vue-demo-forked-zzxsp9?file=%2Fsrc%2FApp.vue

Now the dropdown is only positioned once at the beginning (and the position seems wrong). The isPositioned never changes after that and stays true, I guess because it is never repositioned?

sebbayer avatar Sep 04 '24 14:09 sebbayer

Yes, it will never be repositioned without autoUpdate. Do you have an option to use conditional rendering via v-if (instead of v-show or opacity/visibility/display style) for a floating element?

lozinsky avatar Sep 04 '24 14:09 lozinsky

I understand. The context is that I was thinking about creating a PR for bootstrap-vue-next where the authors are using Floating UI for positioning of the BDropdown.

https://github.com/bootstrap-vue-next/bootstrap-vue-next/blob/main/packages/bootstrap-vue-next/src/components/BDropdown/BDropdown.vue

The show and shown events are fired before the floating <ul> Element has been positioned asynchonously. That leads to problems when focusing the dropdown contents. The current implementation as of 0.24.12 uses v-show together with whileElementsMounted which would not be compatible with isPositioned. The implementation would need to be changed to only use v-if instead of v-show if I understand correctly. Maybe we should close this issue, I open an issue at bootstrap-vue-next and link this issue here.

sebbayer avatar Sep 04 '24 15:09 sebbayer

I'm not sure if it's related, but I've recently noticed a bug with isPositioned in React when the open option is false but the positioning function runs before the floating element is unmounted from the DOM. This leads to isPositioned being true incorrectly upon the next mount since it doesn't get set back to false. I'm pretty sure isPositioned should remain false if open is false (although the positioning can still run, if you want anchoring to work for animating-out floating elements that are partially visible).

atomiks avatar Sep 05 '24 03:09 atomiks

@lozinsky, здравствуйте Павел. Может вам будет интересно присоединиться к разработке порта vue-floating

teleskop150750 avatar Oct 07 '24 04:10 teleskop150750