When positioning dropdowns, tooltips, or context menus with Floating UI (formerly Popper.js), transitions sometimes don't behave like you'd expect. The first time the element is positioned the transition won't originate from the right spot, or it transitions from the prior position. Turns out there's an easy fix!
Floating UI is a JavaScript library which eases the pain of positioning floating elements. Positioning these types of components can be a deceptively hard problem! For example, what if you open a dropdown menu, then window size changes? Your menu might be overflowing the viewport and cut off as a result -- Floating UI solves these kinds of nasty problems.
Following the guide works great -- all until you start adding transitions. When you open a dropdown menu, it shouldn't fly in from the top left of the screen the first it gets opened. The problem becomes even more noticeable when you use Floating UI for something like a context (right click) menu. Transitions for a floating element which is positioned based on a MouseEvent will always appear to originate from where the prior event happened.
Simply use a wrapper element for positioning (only), and style the inner element for looks and transitions.
1<!-- Don't do this -->2<div class="absolute top-0 left-0 transition dropdown-style-classes">3 Dropdown content4</div>56<!-- Do this instead! -->7<div class="absolute top-0 left-0">8 <div class="transition dropdown-style-classes">Dropdown content</div>9</div>
1<!-- Don't do this -->2<div class="absolute top-0 left-0 transition dropdown-style-classes">3 Dropdown content4</div>56<!-- Do this instead! -->7<div class="absolute top-0 left-0">8 <div class="transition dropdown-style-classes">Dropdown content</div>9</div>
The outer element is the element to position with Floating UI, and the inner element should be the actual styled element. This works because the inner element is position: static
by default. The position: absolute
(outer) element can be repositioned by Floating UI without conflicting with other transforms or transitions.
I've ran into this before in the past and fixed it with hacks or setTimeout
calls, but came across this GitHub comment tonight and it worked great for me, so I wanted to share.
Happy Coding! ✌️