There are times when a vanilla <abbr>
or <acronym>
doesn't cut it. What if you want to do something more complex?
Popper.js by Federico Zivolo achieves exactly this. Read on to learn more.
I'm Federico (Fez) Zivolo, UI Specialist at Quid. Born in Italy, I live in Budapest now. I like to help with open source projects on GitHub and I maintain some created by me.
Popper.js is a library to help you position tooltips, popovers, dropdowns and any contextual element that should appear near a button or similar (I call them "poppers"). In short, it's a piece of code that saves you hours of work on any of your projects, since almost all of them end up featuring some "popper".
That's a good question; I'm still trying to figure it out!
Jokes apart, the principle is pretty straightforward. It takes a reference element (usually a button) and a popper element (any element you want to position), it finds out a common offset parent, computes the position of the reference element relative to such parent, and then generates a set of coordinates use to position the popper element.
The hardest part is to consider a whole set of edge cases which range from cross browser compatibilities to box model capillarities, including taking care of the scrollable elements.
The usage is simple:
new Popper(referenceElement, popperElement);
This code will position the popperElement
on the bottom of the provided referenceElement
. Also, you already have access to all the built-in features of the library.
The line also achieves the following:
referenceElement
is too close to the bottom of the viewport, the popperElement
will be positioned on top of it instead.There aren't a lot of available solutions and they all cover a small subset of cases that are instead adequately addressed by Popper.js. The main difference is in the fact that my library doesn't need to manipulate the DOM directly to work.
This fact leads to two strengths: it doesn't have to move the popper node in a different context to properly work and can be integrated into frameworks and view libraries such as React and AngularJS with ease.
You can easily do this to delegate the DOM manipulation:
new Popper(referenceElement, popperElement, {
modifiers: {
applyStyle: { enabled: false },
updateReactData: {
order: 900,
fn(data) {
this.setState({ data });
return data;
}
},
},
});
We have disabled the built-in applyStyle
modifier (they are like middleware, and most of the functionalities provided by Popper.js are provided by them), and defined our custom modifier that only proxies the computed popper coordinates and information to our React component.
Now that you have all the knowledge provided by Popper.js, you can do whatever you need to apply the needed styles to the popper element.
You may have noticed that my custom modifier is returning the data
object at the end. This object is needed because other modifiers may run after it and read the data
object.
This chain-based approach makes Popper.js extensible; you can inject any custom function before or after any of the existing modifiers, disable the ones you don't need, and alter the behavior of others simply modifying the data stored in the data
object.
At the time of the creation of Popper.js, I worked for a company which made large use of tooltips and popovers in their Ember.js application. We had an internal implementation of a positioning library similar to Popper.js, written mostly by two other team members and me. Its code was pretty messy because it had been developed just to work in our particular cases and it was deeply tied to the Ember.js internals.
The time needed to maintain such library became a problem because we spent a significant portion of our time fixing bugs related to it. We then decided to outsource it and use an existing open source library to do the job.
I performed the investigations to find a suitable alternative; the only available choices were Tether and jQuery UI Position. The latter, after some quick tests, ended up being too basic to be used in our context. The only way to use it would have been to fork it and add the missing features.
Tether was very promising, it supported a lot of features and performed quite well. But it had some pretty limiting constraints as the library arbitrarily moved our components away from their original DOM tree context to have them positioned as direct children of the body
tag.
This fact was a major problem because it interfered with the way Ember handled the DOM. One of the problems I remember is that our tests couldn't work because the testing environment of Ember looked for the DOM nodes only inside the root node of the Ember.js application.
The other problem was the limited customizability of it; we couldn't add any additional behavior or feature to it. For instance, we couldn't make a tooltip switch from "right" to "bottom" in case there wasn't enough space on its right. It only allowed "right - left" and "top - bottom".
I wanted to use an existing solution because I just wanted to get the job done, but with these premises, the only viable solution I found was to write my library. My company didn't have time to allocate to write it, so I ended up writing it during a weekend...
Popper.js is getting adopted by more projects every day, and that's cool. My biggest "competitor" discontinued its library (Tether) and they now point to Popper.js, I hope to be able to serve their users as they deserve.
Bootstrap recently merged a PR to use my library in their code base. I hope to see a larger number of contributions on my project as a result.
Other great developers have developed integrations for Popper.js to use it in the most popular libraries such as React, Preact, and Vue.js; others are working to create one for Ember.js. Only Angular is behind and needs a proper integration.
Certain outstanding issues that have to be fixed to handle all the edge cases. More tests have to be written to assure a high quality and reliability, and the API will probably need some makeover in the future. There is a lot of work and not much time available, but I'll do my best to maintain the library and improve it continuously. Some help would be very welcome. 😉
The most innovative idea behind Popper.js is the modularity of it, no other similar libraries let you completely de-opt from any DOM manipulation and delegate them to your code. I think we may see more libraries follow this direction and make the life of other developers easier.
Since the current front-end scenario is populated by a lot of different technologies, the library authors must adopt a model that allows the consumers to integrate them with the existing frameworks and libraries without compromises.
It may sound childish, a lot of folks will tell you that it's a matter of preferences and blah blah... But I think the future of the web development is in the functional, data-driven, development as promoted by Facebook with React. The whole idea of state management "introduced" [1] by those guys saved my team and me hundreds of hours of development already.
If you are getting into web development, first learn the basics of the web: HTML, JavaScript, and CSS. Then, move to any framework or library that follows the data driven and functional principles, if not React, anything wich shares the same idea. Doing this will set you a mindset that will help you to handle and resolve any situation.
[1]: Necessary note, Facebook didn't invent it, they simply promoted within the web development environment.
If you want to be a great developer, remember to have fun along the way. 🙃
Thanks for the interview Federico! If I need tooltips or popovers, I know where to look now.
Remember to check Popper.js demos and Popper.js on GitHub.