Select Link and if Clicke Again Open Popover D3
Building a simple tooltip component that never goes off screen
As a front-end developer, I have seen plenty of UI libraries for tooltips and popovers, but I never felt satisfied by any of them. It can be tricky to make tooltips adhere to responsive design, with so little space on small viewports. Libraries I have tried so far either fail at handling edge cases or require heavy lifting in JavaScript to position the helper element dynamically. I decided to build a web component from scratch instead, to satisfy my needs with a simple approach.
If you just want to see the demo and code, jump straight to the CodePen. đź’…
The base functionality
I used web components to make the UI pattern easy to re-use and to benefit from the lifecycle callbacks they offer. I'll showcase later in this post other advantages from this choice.
The HTML structure is very simple, the tooltip wraps 2 container elements for the label and the dropdown. This will allow both of them to contain rich content, rather than just plain text.
My initial idea is to take advantage of CSS as much as possible. We can easily build a tooltip for desktop screens using the :hover
pseudo-class. The drawback with this approach is that we need a different behaviour on touch screens, where users would expect to be able to dismiss a tooltip either by tapping the label a second time or by tapping away anywhere on the screen.
Handling CSShover
events on touchscreens can be tricky as browsers will interpret them differently. To make things easier, I chose to use a CSS media feature so that only devices that support hovering elements will handle opening/closing tooltips via CSS. Other devices will rely on JS and touch events instead. If you do need to support legacy browsers such as Internet Explorer, don't be scared by its lack of support for the media feature, you can use Browserhacks to specifically target certain browsers your audience rely on.
The CSS needed for this approach is minimal. The idea is to set the container withposition: relative
while the dropdown has a position: absolute
and we can use a combination of left: 50%
and transform: translateX(-50%)
to have the tooltip at the horizontal centre of the label.
To open the tooltip, we use a class with a modifier (following BEM) tooltip--open
. That switches the display
property of the dropdown to block
and trigger a CSS animation for a swift fade-in effect.
JavaScript-wise, using web components allows us to use the Class syntax from ES6 which improves the code's readability. We can use connectedCallback
to set up the event listeners when the custom element is connected to the DOM. We can then toggle the tooltip--open
class on the parent element on touchstart
events.
On top of that, to make sure tooltips are dismissed when the user tap anywhere on the screen after having opened one, we use an event listener on document
, which will remove the tooltip--open
class on any element on the page, unless the current element if within a tooltip itself.
Handling off-screen positions
The main issue with tooltips in a world of responsive design is we can never predict where the label will be placed. Ideally, the tooltip could be triggered from any element, include a word in a paragraph, which is a flowing element based on the size of its container.
This usually ends badly with tooltips going off screen and cropped content, causing frustration for users. There are clever solutions to handle dynamic positioning for elements to always stay visible on screens, such as Popper.js. However, ~6Kb of minified and gzipped JavaScript is quite a lot just to position a little block of text on a screen. Considering the cost of running MBs of JS for users these days, I would prefer a lighter approach.
To reach a simple solution, I scoped down what I needed to the most basic option. Having the dropdown coming from the bottom of the label rather than any position (left, right, top-left, etc), it means the dropdown can only overflow from the horizontal sides. To prevent an overflow, I only need to check on the open event that the element's position doesn't exceed the left and right limits of the screen. In this situation a simple translation of the element using CSS transform
would reset the position back into screen.
In a situation where the label is placed at the left or right end of the screen, the tooltip's dropdown will be fixed to the side of the website's grid. The only remaining situation where the tooltip could go off-screen is if the element is located at the bottom of the page when the user taps on it. Users can still adjust it by scrolling down the page, so the content can be viewed. I don't expect that situation to be problematic enough to introduce more JS code to resolve it programmatically.
The perks of using web components
Web components were a great candidate to build tooltips for their ease of use as part of a design systems. Being able to use a UI pattern just by adding a custom HTML element on a page and not having to worry about invoking any JS code manually is pretty neat.
An event stronger argument in favour of web components was how they interact with the virtual DOM. At carwow we use Elm when we need state management in parts of the website with high client-side interactivity. The downside of having an embedded app using the virtual DOM on a webpage is that it doesn't have direct access to the Window
object. Making a tooltip responsive to the browser's viewport can be tricky in this context. In the case of an Elm app, we could handle that with ports.
Thankfully, we found an alternative solutions with using custom elements inside Elm, which allows for the associated JS to work just as expected. For more information on the possibilities it offers, I'd recommend this talk by Luke Westby at Elm Europe 2018.
The demo
Check out the CodePen below or the component on our lovely design system.
If you have any questions or thoughts on our approach, we'd love to hear them!
Source: https://medium.com/carwow-product-engineering/building-a-simple-tooltip-component-that-never-goes-off-screen-c7039dcab5f9
0 Response to "Select Link and if Clicke Again Open Popover D3"
Postar um comentário