---
navigationLabel: Tutorial
order: 0
---

import {
  Result1,
  Result2,
  Result3,
  Result4,
} from '../../../components/Tutorial';

# Tutorial

In this tutorial you'll learn how to use Popper by building a basic tooltip.

Remember, Popper is not a tooltip library, it's the foundation to build one! If
what you are looking for is a ready to use tooltip lib, take a look at
[Tippy.js](../tippy/).

<x-ad />

## Setting up

Create a new HTML document with two elements, a `<button>` and a tooltip
`<div>`, and pass them to Popper:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Popper Tutorial</title>
  </head>
  <body>
    <button id="button" aria-describedby="tooltip">My button</button>
    <div id="tooltip" role="tooltip">My tooltip</div>

    <script src="__UNPKG_CDN_URL__"></script>
    <script>
      const button = document.querySelector('#button');
      const tooltip = document.querySelector('#tooltip');

      Popper.createPopper(button, tooltip);
    </script>
  </body>
</html>
```

## Styling

Let's give our tooltip some styling:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Popper Tutorial</title>
    <style>
      #tooltip {
        background: #333;
        color: white;
        font-weight: bold;
        padding: 4px 8px;
        font-size: 13px;
        border-radius: 4px;
      }
    </style>
  </head>
  <body>
    <!-- ... -->
  </body>
</html>
```

Here's the result so far:

<Result1 />

## Arrow

Our tooltip is currently just a box. In many UI design systems, this is all
tooltips need, but others prefer to have an arrow that points toward the
reference element.

Add an arrow element with a `data-popper-arrow` attribute like so:

```html
<div id="tooltip" role="tooltip">
  My tooltip
  <div id="arrow" data-popper-arrow></div>
</div>
```

Now for styling:

```css
#arrow,
#arrow::before {
  position: absolute;
  width: 8px;
  height: 8px;
  z-index: -1;
}

#arrow::before {
  content: '';
  transform: rotate(45deg);
  background: #333;
}
```

The `::before` pseudo-element is required because Popper uses `transform` to
position the arrow inside the popper, but we want to use our own `transform` to
rotate the arrow box into a diamond.

Now we need to offset the arrow depending on the popper's current placement.
Popper provides this information with the `data-popper-placement` attribute:

```css
#tooltip[data-popper-placement^='top'] > #arrow {
  bottom: -4px;
}

#tooltip[data-popper-placement^='bottom'] > #arrow {
  top: -4px;
}

#tooltip[data-popper-placement^='left'] > #arrow {
  right: -4px;
}

#tooltip[data-popper-placement^='right'] > #arrow {
  left: -4px;
}
```

> Why the `^=`? This means "starts with", because we can also have variation
> placements like `top-start`.

Here's the result so far:

<Result2 />

## Offset

Our arrow currently overlaps the reference, we can give it a distance of 8px
using the `offset` modifier:

```js
Popper.createPopper(button, tooltip, {
  modifiers: [
    {
      name: 'offset',
      options: {
        offset: [0, 8],
      },
    },
  ],
});
```

Here's the result so far:

<Result3 />

## Functionality

We only want our tooltip to show when hovering or focusing the button.

```css
#tooltip {
  /* ... */
  display: none;
}

#tooltip[data-show] {
  display: block;
}
```

```js
function show() {
  tooltip.setAttribute('data-show', '');
}

function hide() {
  tooltip.removeAttribute('data-show');
}

const showEvents = ['mouseenter', 'focus'];
const hideEvents = ['mouseleave', 'blur'];

showEvents.forEach(event => {
  button.addEventListener(event, show);
});

hideEvents.forEach(event => {
  button.addEventListener(event, hide);
});
```

Here's the final result:

<Result4 />

## Performance

Once we create a popper with `createPopper`, it stays "alive". This means while
scrolling the page, the popper is constantly being updated, even if it is not
visible. We need to create and destroy the popper instance when necessary:

```js
let popperInstance = null;

function create() {
  popperInstance = Popper.createPopper(button, tooltip, {
    modifiers: [
      {
        name: 'offset',
        options: {
          offset: [0, 8],
        },
      },
    ],
  });
}

function destroy() {
  if (popperInstance) {
    popperInstance.destroy();
    popperInstance = null;
  }
}

function show() {
  tooltip.setAttribute('data-show', '');
  create();
}

function hide() {
  tooltip.removeAttribute('data-show');
  destroy();
}
```

## Full code

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Popper Tutorial</title>
    <style>
      #tooltip {
        background: #333;
        color: white;
        font-weight: bold;
        padding: 4px 8px;
        font-size: 13px;
        border-radius: 4px;
        display: none;
      }

      #tooltip[data-show] {
        display: block;
      }

      #arrow,
      #arrow::before {
        position: absolute;
        width: 8px;
        height: 8px;
        z-index: -1;
      }

      #arrow::before {
        content: '';
        transform: rotate(45deg);
        background: #333;
      }

      #tooltip[data-popper-placement^='top'] > #arrow {
        bottom: -4px;
      }

      #tooltip[data-popper-placement^='bottom'] > #arrow {
        top: -4px;
      }

      #tooltip[data-popper-placement^='left'] > #arrow {
        right: -4px;
      }

      #tooltip[data-popper-placement^='right'] > #arrow {
        left: -4px;
      }
    </style>
  </head>
  <body>
    <button id="button" aria-describedby="tooltip">My button</button>
    <div id="tooltip" role="tooltip">
      My tooltip
      <div id="arrow" data-popper-arrow></div>
    </div>

    <script src="__UNPKG_CDN_URL__"></script>
    <script>
      const button = document.querySelector('#button');
      const tooltip = document.querySelector('#tooltip');

      let popperInstance = null;

      function create() {
        popperInstance = Popper.createPopper(button, tooltip, {
          modifiers: [
            {
              name: 'offset',
              options: {
                offset: [0, 8],
              },
            },
          ],
        });
      }

      function destroy() {
        if (popperInstance) {
          popperInstance.destroy();
          popperInstance = null;
        }
      }

      function show() {
        tooltip.setAttribute('data-show', '');
        create();
      }

      function hide() {
        tooltip.removeAttribute('data-show');
        destroy();
      }

      const showEvents = ['mouseenter', 'focus'];
      const hideEvents = ['mouseleave', 'blur'];

      showEvents.forEach(event => {
        button.addEventListener(event, show);
      });

      hideEvents.forEach(event => {
        button.addEventListener(event, hide);
      });
    </script>
  </body>
</html>
```

## Finished

You've now created a basic tooltip using Popper! Of course, there is more you
can do, such as adding animations or interactivity. These are up to you to
explore when creating abstractions for common popper elements like tooltips,
popovers, drop-downs, and more.
