The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
Floating elements are elements that “float” on top of the UI without disrupting the flow of content. Tooltips are examples of floating element; they are short messages that appear on a page when a user hovers over a specific area. We can use tooltips to create user onboarding flows, send updates and reminders to our users, provide more information about a feature, and more.
Popper has long been one of the most popular JavaScript libraries for creating floating elements. However, a new player is in town: its successor, Floating UI.
Floating UI comes with several upgrades. It is cross-platform compatible and can be used in React and React Native applications. It is smaller than Popper; Popper weighs 3kb, and Floating UI is 600 bytes. It is also tree-shakeable by default, while Popper is not. Floating UI is not just an alternative to Popper but an upgrade with several benefits.
In this article, we will learn about Floating UI and how we can use it to create floating elements.
Floating UI is an extensible, low-level library for creating interactive elements like tooltips, popovers, dropdowns, menus and more.
Floating UI exposes primitives, which we can use to position a floating element next to a given reference element. It also supports the web, React, React Native, WebGL, Canvas, and more.
Run the command below to install Floating UI:
npm install @floating-ui/dom
We can also load Floating UI through a CDN using ESM or UMD format like so:
<script type="module"> import * as FloatingUIDOM from 'https://cdn.skypack.dev/@floating-ui/[email protected]'; </script>
computePosition functionThe computePosition function is the heart of Floating UI. It computes the coordinates needed to position the floating element next to its given reference element, which is the element that triggers the floating element.
Let’s build a basic tooltip to see how computePosition works.
We start by setting up the HTML:
<!DOCTYPE html>
<html lang="en">
<body>
<button id="button" aria-describedby="tooltip">My button</button>
<div id="tooltip" role="tooltip">My tooltip oltip with more content</div>
<script src="/index.js" type="module" />
</body>
</html>
Next, we style the tooltip and set its position to absolute so it floats and doesn’t disrupt the flow of the other content.
#tooltip {
color: #fff;
background: #363636;
font-size: 1.2rem;
padding: 10px 15px;
border-radius: 8px;
position: absolute;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1), 0 3px 3px rgba(0, 0, 0, 0.05);
}
button {
border-radius: 8px;
border: none;
outline: none;
font-size: 1.2rem;
cursor: pointer;
padding: 10px 15px;
color: #fff;
background: rgb(48, 19, 129);
}
Having set up the structure and styling for the tooltip, let’s work on the functionality:
import {computePosition} from 'https://cdn.skypack.dev/@floating-ui/[email protected]';
const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');
computePosition(button, tooltip).then(({x, y}) => {
// Do things with `x` and `y`
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`,
});
});
The button is the reference element, and the tooltip is the floating element.
We can change the placement of the tooltip to different positions like so:
computePosition(button, tooltip, {
placement: 'top-start',
})then(({ x, y }) => {
//other code below
};
There are 12 core positions we can place elements:
left-start, left and left-endtop-start, top and top-endright-start, right and right-endbottom-start, bottom and bottom-endThe default position of a floating element is bottom.
Middleware is a piece of code that runs between the call of computePosition and its eventual return to modify or provide data to the consumer. It alters the placement and behavior of floating elements.
Middleware is how every single feature beyond the basic placement positioning is implemented.
Floating UI provides several middlewares:
offset places spacing between the reference element and the floated elementshift shifts the floated element to ensure its entire content is always in view. It also ensures that the element does not overflow outside the viewport by handling clipping and overflow issuesflip modifies the coordinates for us, such that the bottom placement automatically positions the floating element at the bottom if it is too close to the top of the viewport and vice versasize handles the resizing of the floated elementautoPlacement automatically chooses the placement of the floated element by selecting the position with the most space availableinline improves positioning for inline reference elements that span over multiple lines, such as hyperlinksLet’s extend the behavior of the basic tooltip with some of these middlewares:
computePosition(button, tooltip, {
placement: "top",
middleware: [offset(4), flip(), shift({padding: 5})],
}).then(({ x, y }) => {
//other code below
});
Above, we use offset to add a 4px spacing between the tooltip and the button.
Besides fixing content clipping issues, the shift middleware accepts an options object where we define the spacing between the tooltip and the edge of the viewport. We set the spacing to 5px.
The order in which we arrange the middlewares is important; offset must always be at the beginning of the array.
Currently, the tooltip is always visible. However, it should only show when we hover over the button.
Let’s set up that functionality:
function setUpTooltip() {
computePosition(button, tooltip, {
placement: "top",
middleware: [offset(4), flip(), shift({ padding: 5 })],
}).then(({ x, y }) => {
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`,
});
});
}
function showTooltip() {
tooltip.style.display = "block";
setUpTooltip();
}
function hideTooltip() {
tooltip.style.display = "none";
}
Above, we move the tooltip logic into a function, setUpTooltip, so we can call that function when we want the tooltip to show.
We also create two functions, hideTooltip and showTooltip. hideTooltip sets the tooltip’s display to none. showTooltip sets the tooltip’s display to block and class setUpTooltip.
We want to call hideTooltip when we hover away from the button and call showTooltip when we hover over the button:
[
["mouseenter", showTooltip],
["mouseleave", hideTooltip],
].forEach(([event, listener]) => {
button.addEventListener(event, listener);
});
Here, we attach the event listeners and the functions to the button. With this, the tooltip will only appear on hover.
We have the final code for the tooltip below:
import {
computePosition,
flip,
shift,
offset,
} from "https://cdn.skypack.dev/@floating-ui/[email protected]";
const button = document.querySelector("#button");
const tooltip = document.querySelector("#tooltip");
function setUpTooltip() {
computePosition(button, tooltip, {
placement: "top",
middleware: [offset(4), flip(), shift({ padding: 5 })],
}).then(({ x, y }) => {
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`,
});
});
}
function showTooltip() {
tooltip.style.display = "block";
setUpTooltip();
}
function hideTooltip() {
tooltip.style.display = "none";
}
[
["mouseenter", showTooltip],
["mouseleave", hideTooltip],
["focus", showTooltip],
["blur", hideTooltip],
].forEach(([event, listener]) => {
button.addEventListener(event, listener);
});
We can easily integrate Floating UI into React applications.
First, we have to install the React library into a React application like so:
npm install @floating-ui/react-dom
Floating UI provides a useFloating Hook we can use in React applications. Let’s use this Hook to set up the basic tooltip in React:
import { useFloating, shift, offset, flip } from "@floating-ui/react-dom";
export default function App() {
const { x, y, reference, floating, strategy } = useFloating({
placement: "right",
middleware: [offset(4), flip(), shift({ padding: 5 })],
});
return (
<>
<button ref={reference}>Button</button>
<div
id="tooltip"
ref={floating}
style={{ top: y, left: x }}
>
Tooltip
</div>
</>
);
}
The useFloating Hook accepts all of computePosition‘s options, meaning we can define the placement of a tooltip and add middleware.
In this article, we have learned about floating UI, how it works, its different features, and how to integrate it into React applications.
While Floating UI offers a few benefits over Popper, one thing I would have loved to see is a demo showing how to conditionally display tooltips on hover for React. Sadly, the documentation does not cover that. Also, there is little or no developer content or support available, as this is a new library. So while Floating UI is a great new tool, these are things we should take into account when working with it.
Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
server-side
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>

:has(), with examplesThe CSS :has() pseudo-class is a powerful new feature that lets you style parents, siblings, and more – writing cleaner, more dynamic CSS with less JavaScript.

Kombai AI converts Figma designs into clean, responsive frontend code. It helps developers build production-ready UIs faster while keeping design accuracy and code quality intact.

Discover what’s new in The Replay, LogRocket’s newsletter for dev and engineering leaders, in the October 22nd issue.

John Reilly discusses how software development has been changed by the innovations of AI: both the positives and the negatives.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now