
Floating UI: Stop Fighting the DOM for Overlay Positioning
Getting tooltips, dropdowns, and popovers to stay where they belong, especially when scrolling or resizing, is a nightmare. Floating UI is the library that solves this once and for all, with a tiny footprint and robust positioning logic.
by Sunil Band
The Perennial Pain of Overlay Positioning
If you've built anything beyond a static marketing page, you've probably wrestled with positioning overlays. Tooltips, dropdowns, popovers, context menus – they all seem deceptively simple until you hit the real world. Suddenly, they're clipping off-screen, jumping around on scroll, or refusing to align correctly when their content changes size. You reach for position: absolute or fixed, maybe even transform: translate, and quickly find yourself trapped in a brittle CSS maze, battling z-index wars and calculating offsets in JavaScript.
I've been there countless times. My first attempts usually involve getBoundingClientRect() and some manual math, which inevitably breaks when the viewport resizes, the page scrolls, or the content inside the overlay changes. It's a never-ending game of whack-a-mole, and frankly, it's a huge waste of engineering time for something that feels like it should be simple. This is exactly the problem Floating UI solves, and it does so with elegance and efficiency.
Why Floating UI is a Game Changer
Floating UI isn't just another utility library; it's a fundamental shift in how we approach positioning dynamic elements. It abstracts away all the complexity of calculating positions, detecting collisions, flipping, shifting, and even managing the dreaded scroll event. Before Floating UI, you either rolled your own brittle solution or pulled in a massive UI library just for its positioning engine. Floating UI gives you that core, robust engine without the rest of the baggage.
The library operates on two core concepts: a floating element (your tooltip, popover, etc.) and a reference element (the button, input, or icon it's attached to). You tell Floating UI which element is which, define your desired placement (e.g., 'top', 'bottom-start'), and it handles the rest. It's framework-agnostic, tiny (under 5kb), and incredibly performant.
Getting Started with Floating UI
Let's walk through a common example: a simple tooltip. We want the tooltip to appear below a button, but if there's not enough space, it should flip to the top. It should also stay with the button even if the page scrolls.
First, install it:
npm install @floating-ui/react
# or for vanilla JS
npm install @floating-ui/domI'll use the @floating-ui/react package for this example, as it provides convenient hooks that integrate seamlessly with React's lifecycle. However, the core logic is identical for the vanilla @floating-ui/dom package.
import React, { useState, useRef } from 'react';
import { useFloating, useHover, useFocus, useDismiss, useRole, useInteractions, offset, flip, shift, autoUpdate } from '@floating-ui/react';
interface TooltipProps {
content: string;
children: React.ReactNode;
}
function Tooltip({ content, children }: TooltipProps) {
const [isOpen, setIsOpen] = useState(false);
const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
placement: 'bottom-start', // Initial placement: bottom, aligned to the start
whileElementsMounted: autoUpdate, // Keep updating position while elements are mounted
middleware: [
offset(8), // Keep 8px distance from the reference element
flip(), // If bottom doesn't fit, flip to top, then left/right
shift(), // If still not fitting, shift along the available axis
],
});
const hover = useHover(context, { move: false }); // Show/hide on hover
const focus = useFocus(context); // Show/hide on focus
const dismiss = useDismiss(context); // Hide on escape key or outside click
const role = useRole(context, { role: 'tooltip' }); // Accessibility role
const { getReferenceProps, getFloatingProps } = useInteractions([
hover,
focus,
dismiss,
role,
]);
return (
<>
{/* This is our reference element. The tooltip will position relative to it. */}
<span ref={refs.setReference} {...getReferenceProps()}>
{children}
</span>
{isOpen && (
<div
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
className="tooltip"
>
{content}
</div>
)}
<style jsx>{`
.tooltip {
background: #333;
color: #fff;
padding: 8px 12px;
border-radius: 4px;
font-size: 14px;
z-index: 1000;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
`}</style>
</>
);
}
export default function App() {
return (
<div style={{ padding: '150px', display: 'flex', gap: '20px', justifyContent: 'center', alignItems: 'center', height: '100vh', flexDirection: 'column' }}>
<h1>Floating UI Demo</h1>
<Tooltip content="Hello, I'm a tooltip!">
<button>Hover me</button>
</Tooltip>
<div style={{ height: '500px', width: '1px', background: '#ccc' }}></div> {/* Spacer to force scroll */}
<Tooltip content="I'm another tooltip, try scrolling!">
<button>Focus me</button>
</Tooltip>
</div>
);
}Let's break down what's happening:
-
useFloating: This is the core hook. We pass itopenandonOpenChangeto control the tooltip's visibility.placement: 'bottom-start'tells Floating UI to try and place the floating element below the reference, aligned to its start. -
whileElementsMounted: autoUpdate: This is crucial. It automatically re-positions the tooltip whenever the reference or floating element moves, resizes, or the page scrolls. No more manual event listeners! -
middleware: This is where the magic happens. We define an array of functions that Floating UI runs to determine the final position:
-
offset(8): Adds 8 pixels of spacing between the button and the tooltip. -
flip(): If the initialbottom-startplacement causes the tooltip to go off-screen, it triestop-start, thenbottom-end,top-end, and so on, until it finds a placement that fits. This is powerful for responsive UIs. -
shift(): Ifflipstill can't find a perfect fit,shiftwill slide the tooltip along its current axis to keep it entirely within the viewport. This prevents clipping even in tight spaces.
-
-
useInteractions: This hook combines various interaction hooks likeuseHover,useFocus,useDismiss, anduseRoleinto a single, cohesive API. This handles common tooltip behaviors and ensures accessibility attributes are correctly applied. -
refs.setReferenceandrefs.setFloating: These are ref setters that Floating UI uses to get references to your DOM elements. This is how it knows what to position relative to what. -
floatingStyles: This object contains theleft,top,position, andtransformCSS properties calculated by Floating UI. You apply these directly to your floating element.
With this setup, you get a robust tooltip that automatically adapts to its environment, stays within the viewport, and handles common user interactions out of the box. The amount of boilerplate saved, and the peace of mind knowing it just works, is immense.
More Complex Scenarios
Floating UI isn't limited to simple tooltips. It excels in more complex scenarios like:
- Dropdown menus: You might want a dropdown to open directly below a button but expand upwards if there's not enough space.
fliphandles this naturally. - Context menus: These often appear at the mouse cursor position. Floating UI can take arbitrary coordinates as a reference, making this trivial.
- Modals or popovers within scrollable containers: If your reference element is inside a
divwithoverflow: auto, Floating UI still tracks it correctly. - Nested overlays: A tooltip on an item within a dropdown menu? No problem. The library is designed to handle multiple layers of floating elements.
The middleware array is where you customize behavior. Beyond offset, flip, and shift, there are other useful options like arrow (to position a tooltip arrow), hide (to detect if the reference is obscured), and size (to adjust the floating element's size to fit).
The Trade-Offs
While Floating UI solves a significant pain point, it's important to acknowledge its place in the ecosystem. It's a low-level primitive for positioning. It doesn't provide any UI components or styling. You're still responsible for the look and feel of your overlays and managing their open/closed state.
This is by design, and frankly, it's a strength. It means you can integrate Floating UI into any framework, with any design system, without fighting opinionated components. However, if you're looking for a complete, batteries-included solution for all your UI components, you'll still need a library like Material UI or Radix UI (which, incidentally, uses Floating UI under the hood for its positioning). Floating UI is the foundational layer, not the entire house.
Another minor consideration is the initial flash of unstyled content. Since floatingStyles are applied after rendering, there can be a brief moment where the floating element is in its default position before JavaScript corrects it. This is usually imperceptible for small, fast-opening elements, but for larger, slower elements, you might want to hide the floating element initially with visibility: hidden and then make it visible after the first position calculation.
Wrapping up
Stop writing custom positioning logic. Seriously. It's a rabbit hole that never ends well. Floating UI is the industry standard for a reason – it's robust, tested, and handles all the edge cases you'd rather not think about. It's the kind of library that makes you forget you ever had a problem in the first place.
If you've been battling position: absolute and getBoundingClientRect() for your overlays, give Floating UI a try. Clone the example above, or better yet, head over to the Floating UI documentation and experiment with their interactive demos. You'll quickly see how it simplifies complex positioning scenarios and frees you up to focus on the actual functionality of your application.

Internationalization in Next.js: Beyond the Basic `i18n.js` File
Setting up i18n in Next.js often starts with a simple JSON file, but real-world applications quickly outgrow that. `next-intl` offers a robust solution that integrates deeply with Next.js features, including Server Components, to manage translations more effectively and avoid common pitfalls.

Beyond the Canvas: When Your Frontend Becomes an AI Art Studio
Stable Diffusion, Midjourney, DALL-E 3 — these names are everywhere. But for frontend developers, the interaction often stops at calling an API or embedding a widget. InvokeAI, however, presents a different paradigm: bringing the full power of an AI art engine directly into a sophisticated web appli

Beyond the Marketing: When a No-Code Editor Becomes Your Component Playground
I've been wary of 'no-code' tools. They often promise the moon but deliver a walled garden, abstracting away too much and leaving you stranded when you need real customizability. GrapesJS, however, isn't just another drag-and-drop editor; it's a web builder framework. This distinction fundamentally


















