Getting started with Floating UI
Tags: webdev
Published: 2022-03-28 14:08:33

**Written by [Nefe James](https://blog.logrocket.com/author/nefejames/)✏️**

## Introduction

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](https://blog.logrocket.com/popper-vs-floating-ui/) 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](https://floating-ui.com).

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.

## About Floating UI

Floating UI is an extensible, low-level library for creating [interactive elements](https://blog.logrocket.com/build-interactive-blog-with-react-sandpack/) 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.

## Getting started

Run the command below to install Floating UI:

```shell
npm install @floating-ui/dom
```

We can also load Floating UI through a CDN using ESM or UMD format like so:

```shell
<script type="module">
  import * as FloatingUIDOM from 'https://cdn.skypack.dev/@floating-ui/dom@0.3.1';
</script>
```

## The `computePosition` function

The `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:

```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.

```css
#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:

```js
import {computePosition} from 'https://cdn.skypack.dev/@floating-ui/dom@0.2.0';

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:

```js
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-end`
*   `top-start`, `top` and `top-end`
*   `right-start`, `right` and `right-end`
*   `bottom-start`, `bottom` and `bottom-end`

The default position of a floating element is `bottom`.

## Middleware

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 element
*   `shift` 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 issues
*   `flip` 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 versa
*   `size` handles the resizing of the floated element
*   `autoPlacement` automatically chooses the placement of the floated element by selecting the position with the most space available
*   `inline` improves positioning for inline reference elements that span over multiple lines, such as hyperlinks

Let’s extend the behavior of the basic tooltip with some of these middlewares:

```js
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.

## Showing tooltips on hover

Currently, the tooltip is always visible. However, it should only show when we hover over the button.

Let’s set up that functionality:

```js
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:

```js
[
  ["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:

```js
import {
  computePosition,
  flip,
  shift,
  offset,
} from "https://cdn.skypack.dev/@floating-ui/dom@0.2.0";

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);
});
```

## Using Floating UI with React

We can easily integrate Floating UI into React applications.

First, we have to install the React library into a React application like so:

```shell
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:

```js
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.

## Conclusion

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.

---

## [LogRocket](https://logrocket.com/signup/): Full visibility into your web apps

![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)

[LogRocket](https://logrocket.com/signup/) is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

[Try it for free](https://logrocket.com/signup/).