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! Follow the tutorial below to learn how to use Popper.
They are small and unobtrusive.
Alternatively, support us on Open Collective!
Setting up
Create a new HTML document with two elements, a <button>
and a tooltip
<div>
, and pass them to Popper:
<!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="https://unpkg.com/@popperjs/core@2"></script>
<script>
const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');
const popperInstance = Popper.createPopper(button, tooltip);
</script>
</body>
</html>
Styling
Let's give our tooltip some styling:
<!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:
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:
<div id="tooltip" role="tooltip">
My tooltip
<div id="arrow" data-popper-arrow></div>
</div>
Now for styling:
#arrow,
#arrow::before {
position: absolute;
width: 8px;
height: 8px;
background: inherit;
}
#arrow {
visibility: hidden;
}
#arrow::before {
visibility: visible;
content: '';
transform: rotate(45deg);
}
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:
#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 liketop-start
.
Here's the result so far:
Offset
Our arrow currently overlaps the reference, we can give it a distance of 8px
using the offset
modifier:
const popperInstance = Popper.createPopper(button, tooltip, {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
});
Here's the result so far:
Functionality
We only want our tooltip to show when hovering or focusing the button.
#tooltip {
/* ... */
display: none;
}
#tooltip[data-show] {
display: block;
}
function show() {
tooltip.setAttribute('data-show', '');
// We need to tell Popper to update the tooltip position
// after we show the tooltip, otherwise it will be incorrect
popperInstance.update();
}
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:
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 can disable the event listeners when the tooltip is hidden to
optimize it:
function show() {
// Make the tooltip visible
tooltip.setAttribute('data-show', '');
// Enable the event listeners
popperInstance.setOptions((options) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: true },
],
}));
// Update its position
popperInstance.update();
}
function hide() {
// Hide the tooltip
tooltip.removeAttribute('data-show');
// Disable the event listeners
popperInstance.setOptions((options) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
}
Full code
<!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;
background: inherit;
}
#arrow {
visibility: hidden;
}
#arrow::before {
visibility: visible;
content: '';
transform: rotate(45deg);
}
#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="https://unpkg.com/@popperjs/core@2"></script>
<script>
const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');
const popperInstance = Popper.createPopper(button, tooltip, {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
});
function show() {
// Make the tooltip visible
tooltip.setAttribute('data-show', '');
// Enable the event listeners
popperInstance.setOptions((options) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: true },
],
}));
// Update its position
popperInstance.update();
}
function hide() {
// Hide the tooltip
tooltip.removeAttribute('data-show');
// Disable the event listeners
popperInstance.setOptions((options) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
}
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.
Edit this page