isPositioned only becomes true after setting the open option to false
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:
- Open the codesandbox link
- Click on the button multiple times
- See how
isPositionedonly becomes true afteropenis set tofalse.
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
Seems like the sandbox is private:
Sorry @oleksandr-danylchenko, it should be accessible now.
@lozinsky can you take a look here?
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 usingv-showinstead, avoid thewhileElementsMountedprop.
Eventually isPositioned became true after setting isOpen to false, because the element is positioned via autoUpdate.
@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?
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?
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.
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).
@lozinsky, здравствуйте Павел. Может вам будет интересно присоединиться к разработке порта vue-floating