Show the tooltip above the cursor if there is enough space in the viewport; otherwise, position it

I'm encountering an issue with positioning a tooltip that I'm creating.

The tooltip's CSS is set to position: absolute, and I've implemented a mouse event handler that adjusts its top and left based on the pageX and pageY.

While I could simply set the top as pageY and left as pageX, this would cause the tooltip to always appear at the bottom-right. My goal is to have it show up at the top-right if space allows, or fallback to the bottom-right position if it goes beyond the viewport on the Y-axis.

Currently, I'm struggling to figure out how to display the tooltip at the top-right of the mouse cursor. I'm unsure where to start in terms of detecting if it would be within the viewport. Can anyone provide guidance?

$('p').on('mouseenter', function(e) {
    $(tt).css('top', e.pageY - $(tt).css('height'));
    $(tt).css('left', e.pageX);
    $(tt).appendTo('body');
}).on('mousemove', function(e) {
    $(tt).css('top', e.pageY - $(tt).css('height'));
    $(tt).css('left', e.pageX);    
}).on('mouseleave', function(e) {
    $(tt).detach();
});

Check out the example on JSFiddle

Answer №1

When it comes to working with tooltips, especially in conjunction with jQuery, there are various approaches you can take. The method outlined here may not be the most intuitive choice for some, but with a few adjustments, it can function as intended.

var tt = document.createElement('div');
tt.id = "tt";

$('p').on('mouseenter', function(e) {
    var curPos = $( this ).offset().top - $( window ).scrollTop();
    var inView = (curPos < 250) ? 0 : 250;
    $(tt).css('top', e.pageY - inView);
    $(tt).css('left', e.pageX);
    $(tt).append($( this ).attr("data-myId"));
    $(tt).appendTo('body');
}).on('mousemove', function(e) {
    $(tt).css('top', e.pageY - $(tt).css('height'));
    $(tt).css('left', e.pageX);    
}).on('mouseleave', function(e) {
    $(tt).empty($( this ).attr("data-myId"));
    $(tt).detach();
});

You can view the complete changes on JSFiddle.

This implementation takes advantage of jQuery's offset() and scrollTop() functions to determine the position of an element within the visible part of the page.

jQuery's API documentation explains that the .offset() method retrieves the current position of an element relative to the document. It also mentions that the vertical scroll position (.scrollTop()) reflects the number of hidden pixels above the visible area.

We leverage these functions by subtracting the number of hidden pixels from the element's position relative to the document. It's important to note that the offset method returns an object with top and left properties.

var curPos = $( this ).offset().top - $( window ).scrollTop();

With the tooltip height set at a fixed 250px, we can determine whether the element is positioned within the window's visible area by comparing its location. If it's below 250px, no adjustments are made, keeping the tooltip beneath the cursor. If it exceeds 250px, we subtract 250px to place the tooltip above the cursor.

The content for the tooltips can be derived from the data-myId value using

$(tt).append($( this ).attr("data-myId"));
, while
$(tt).empty($( this ).attr("data-myId"));
clears it on mouseleave. I hope this explanation clarifies things!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Setting up a Node.js project in your local environment and making it

I need help installing my custom project globally so I can access it from anywhere in my computer using the command line. However, I've been struggling to make it work. I attempted the following command: npm install -g . and some others that I can&ap ...

Angular 5 Rxjs Subject subscription not activating across various components

Currently, I'm utilizing rxjs and subjects to efficiently update two components within my application. Within a service, I have set up a subscription to a subject. However, upon calling the .next method on the Subject, only one of the components is b ...

What is the best way to layer four images in a 2x2 grid over another image using CSS as the background

I am attempting to place 4 images of the same size on a 5th image defined as the background. Currently, it looks like this: It works perfectly when the height is fixed, but in my case, the height may vary causing this issue: This problem isn't surp ...

How does the Jquery keyup function know when to automatically activate after typing stops and clicking anywhere on the body?

My Keyup & change event listeners are working well, but there's an issue when the user stops typing and clicks anywhere on the page - an ajax request is triggered again. Can anyone help me identify the problem? Below is my code: $(".eventcla ...

Even when applying a class, the CSS link:hover style will only affect the initial occurrence

I've hit a wall on this issue and can't seem to find a solution. I styled a few links using classes, but it seems that only the first link is accepting the :hover and :visited state styling. I made sure to use classes to style all of them. Not su ...

How to Capture Clicks on Any DOM Element in React

Currently working on a web project using React and Node. My goal is to monitor all clicks across the entire document and verify if the previous click occurred within a 2-minute timeframe. ...

Analyzing the current time against a user-inputted time using Javascript

Looking at this html and javascript code, the goal is to compare an input time with the current time. If the input time is less than 2 hours, "Less time" should be displayed in the label; if it's more than 2 hours, then "sufficient time" should appear ...

Why does middleware get invoked multiple times in node.js when redirecting to a page using Expressjs?

Can you help me understand how middleware functions are invoked in an Express.js app? I have the following code snippet: // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jad ...

Update the input component's typing area line color from its default shade

Is there a way to customize the color of the line in the typing area for the input component? I haven't been able to find any information on using Sass variables or another method to achieve this. For reference, here is a Plunker example <ion-it ...

Unable to utilize the post method in Node.js

<form class="ui form" action"/submit" method="post"> <div class="field"> <label>Time dedicated to studying:</label> <input type="number" name="study" placeholder="Total time spent on studies:"> ...

You can only use the 'iframe' tag as a child of the 'noscript' tag. Were you trying to use 'amp-iframe' instead? - NextJs

We are currently experiencing an issue with AMP errors. The error message states: "The tag 'iframe' may only appear as a descendant of tag 'noscript'. Did you mean 'amp-iframe'?" It's important to note that custom JavaSc ...

What is the best way to increase the row spacing in an Ant Design Table?

I have a table with expandable rows in antd, and I am looking to add some vertical space between the rows. I've tried using the rowClassName property provided by antd, but it did not work as expected. I also attempted to use a custom component, but th ...

Securing access across multiple routes in a React application

I am facing a challenge in my React app where I need to verify the logged-in state before allowing access to multiple routes. Despite consulting various resources like Stack Overflow for solutions such as creating a Private Route, I have only found example ...

Send a $_SESSION value and additional input data (select) from jQuery to a script called saveindb.php for saving in the database

I am working on passing select fields and a session id dynamically to a php file for saving data into a database. Assuming I have the following code setup: <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script&g ...

Queueing in jQuery on a selected group of elements

I have a group of images inside a div that are tagged with different class names for filtering purposes. I am attempting to create a sequence of effects (simple animated show/hide) on these images. <div id="myDiv"> <img class="tag1 tag2 tag3" ...

Employ a directive within a different directive

I have developed a directive for displaying SVG icons and now I want to use this icon directive within another directive. Icon directive: <icon p="shopping-add"></icon> What I am aiming for: app.directive("product", function() { return { ...

A guide on how to selectively blur and make the background transparent in jgrowl notifications without affecting the content

After some experimentation, I found that making the jGrowl notification background both transparent and blurry was not possible. When applying blur to the background, the content also became blurry, which is not the desired effect. If you want a transparen ...

In a Vue component, use JavaScript to assign the data property in object 2 to object 1 when their keys match

Could use some assistance here as I believe I'm getting close to a solution, I have a form object that needs updating based on matching keys with an imported object. For example, form.title should be set to the value in article.title. I've att ...

Combining two-digit values

As a newcomer to JavaScript, I've been working on creating a basic calculator to practice my skills. However, I've run into an issue. When entering a double-digit number, the calculator is adding the digits together instead of treating them as se ...

Prevent elements from displaying until Masonry has been properly set up

My goal is to merge Masonry elements with existing ones. Currently, the items appear before Masonry initializes then quickly adjust into position a moment later. I want them to remain hidden until they are in their proper place. This is the snippet (with ...