What is the best way to trigger a tooltip when an input field is clicked?

I want to implement a form that displays tooltips whenever a user clicks or focuses on an input field, and the tooltip should disappear when the user clicks elsewhere. While I understand the basics of using JavaScript's getElementById and click event listeners, I'm unsure of how to toggle the CSS code for tooltips that currently only work on hover. I do not want to use the :active pseudo-class for this functionality.

HTML:

<p>
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vitae consequat dui, ut ultricies tortor. Fusce imperdiet augue sit amet magna lobortis eleifend. Sed gravida consectetur magna vitae luctus. Suspendisse potenti. Cras luctus porttitor viverra. Aenean ac magna ullamcorper, ullamcorper sem non, mattis felis. Morbi ultricies pretium dui, quis posuere sapien tristique sit amet. Sed et velit tincidunt, convallis enim sed, imperdiet lectus. In quis diam aliquet, pharetra nisi et, interdum eros. Nullam rutrum lectus at est lacinia facilisis. Nullam eu gravida felis. Suspendisse ut magna id nisi fringilla venenatis. Cras facilisis tellus at erat fermentum congue. Nullam dapibus varius nibh, eu pharetra leo vehicula nec.
</p>
<label>Username</label>
<div data-tip="Only A-Z">
  <span></span>
  <input id='username-input' type="text">
</div>
<label>Password</label>
<div data-tip="8 characters minimum">
  <span></span>
  <input id='password-input' type="text">
</div>
<label>Email</label>
<div data-tip="E-mail is only for registration">
  <span></span>
  <input id='email-input' type="text">
</div>

CSS:

[data-tip] {
    position: relative;

}

[data-tip]::before {
    content: '';
    display: none;
    border-left: 15px solid transparent;
    border-right: 15px solid transparent;
    border-top: 15px solid #ccc;
    position: absolute;
    top: -10px;
    left: 15px;
    z-index: 10;
    font-size: 1em;
    line-height: 2em;
    width: 0;
    height: 0;
}

[data-tip] > span {
  display: none;
  border-left: 16px solid transparent;
    border-right: 16px solid transparent;
    border-top: 16px solid black;
    position: absolute;
    top: -9px;
    left: 14px;
    z-index: 7;
    font-size: 1em;
    line-height: 2em;
    width: 0;
    height: 0;

}

[data-tip]::after {
    display: none;
    content: attr(data-tip);
    position: absolute;
    top: -54px;
    left: 0px;
    border: 1px solid black;
    padding: 10px 20px;
    background-color: #ccc;
    color: black;
    z-index: 9;
    font-size: 0.75em;
    height: 4em;
    text-align: center;
    vertical-align: middle;
    line-height: 2em;
    -webkit-border-radius: 0.5em;
    -moz-border-radius: 0.5em;
    border-radius: 0.5em;
    box-sizing: border-box;
    white-space: nowrap;
    word-wrap: normal;
}

[data-tip]:hover > span,
[data-tip]:hover::before,
[data-tip]:hover::after {
    display: block;
}

JavaScript:

input = document.getElementById('email-input');
input.addEventListener('click', function() {
    /* Need help toggling CSS code here */
});

jsfiddle link

Answer №1

Yes, handling this with JavaScript is the correct approach:

var tooltips = document.querySelectorAll('.tooltip');
tooltips.forEach(function(tooltip){
  tooltip.addEventListener("click", function(e){
      tooltips.forEach(function(tip){
        tip.classList.remove("active");
      });
      this.classList.add("active");
  });

});
[data-tip] {
    position: relative;

}

[data-tip]::before {
    content: '';
    display: none;
    border-left: 15px solid transparent;
    border-right: 15px solid transparent;
    border-top: 15px solid #ccc;
    position: absolute;
    top: -10px;
    left: 15px;
    z-index: 10;
    font-size: 1em;
    line-height: 2em;
    width: 0;
    height: 0;
}

[data-tip] > span {
  display: none;
  border-left: 16px solid transparent;
    border-right: 16px solid transparent;
    border-top: 16px solid black;
    position: absolute;
    top: -9px;
    left: 14px;
    z-index: 7;
    font-size: 1em;
    line-height: 2em;
    width: 0;
    height: 0;

}

[data-tip]::after {
    display: none;
    content: attr(data-tip);
    position: absolute;
    top: -54px;
    left: 0px;
    border: 1px solid black;
    padding: 10px 20px;
    background-color: #ccc;
    color: black;
    z-index: 9;
    font-size: 0.75em;
    height: 4em;
    text-align: center;
    vertical-align: middle;
    line-height: 2em;
    -webkit-border-radius: 0.5em;
    -moz-border-radius: 0.5em;
    border-radius: 0.5em;
    box-sizing: border-box;
    white-space: nowrap;
    word-wrap: normal;
}

.tooltip.active > span,
[data-tip].active::before,
[data-tip].active::after {
  display: block;
  }
<p>
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vitae consequat dui, ut ultricies tortor. Fusce imperdiet augue sit amet magna lobortis eleifend. Sed gravida consectetur magna vitae luctus. Suspendisse potenti. Cras luctus porttitor viverra. Aenean ac magna ullamcorper, ullamcorper sem non, mattis felis. Morbi ultricies pretium dui, quis posuere sapien tristique sit amet. Sed et velit tincidunt, convallis enim sed, imperdiet lectus. In quis diam aliquet, pharetra nisi et, interdum eros. Nullam rutrum lectus at est lacinia facilisis. Nullam eu gravida felis. Suspendisse ut magna id nisi fringilla venenatis. Cras facilisis tellus at erat fermentum congue. Nullam dapibus varius nibh, eu pharetra leo vehicula nec.
</p>
<label>Username</label>
<div class="tooltip" data-tip="Only A-Z">
  <span></span>
  <input id='username-input' type="text">
</div>
<label>Password</label>
<div class="tooltip" data-tip="8 characters minimum">
  <span></span>
  <input id='password-input' type="text">
</div>
<label>Email</label>
<div class="tooltip" data-tip="E-mail is only for registration">
  <span></span>
  <input id='email-input' type="text">
</div>

Answer №2

Forget javascript, CSS input can handle this with its focus pseudo-class,

I've made some changes to your code, try running the snippet below:

label { display: inline-block; }

div {
position: relative;
}

input ~ span {
  display: none;
position: absolute;
bottom: 30px;
}

input ~ span span {
  display: block;
  position: relative;
  border: 1px solid black;
  z-index: 3;
  background-color: #ccc;
  font-size: 1em;
line-height: 2em;
  border-radius: 0.5em;
  box-sizing: border-box;
  white-space: nowrap;
word-wrap: normal;
color: black;
  height: 4em;
  text-align: center;
  vertical-align: middle;
-webkit-border-radius: 0.5em;
-moz-border-radius: 0.5em;
  padding: 10px 20px;
}

input ~ span::before {
content: '';
display: none;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-top: 15px solid #ccc;
position: absolute;
bottom: -10px;
  left: 14px;
z-index: 9;
font-size: 1em;
line-height: 2em;
width: 0;
height: 0;
}

input ~ span::after {
content: '';
display: none;
border-left: 16px solid transparent;
border-right: 16px solid transparent;
border-top: 15px solid black;
position: absolute;
  bottom: -11px;
  left: 13px;
z-index: 1;
font-size: 1em;
line-height: 2em;
width: 0;
height: 0;
}

input:focus ~ span::before,
input:focus ~ span::after,
input:focus ~ span {
 display: block;
}
<p>
 Your unique content here.
</p>
<label>Username</label>
<div>
  <input id='username-input' type="text">
  <span><span>Only A-Z</span></span>
</div>
<label>Password</label>
<div>
  <input id='password-input' type="text">
  <span><span>8 characters minimum</span></span>
</div>
<label>Email</label>
<div >
  <input id='email-input' type="text">
  <span>
    <span>E-mail is only for registration</span>
  </span>
</div>

Answer №3

After playing around with your code a bit, I've come to some conclusions: You made things more complicated than needed by using pseudo-elements ::before and ::after to build your tooltip. It would be simpler if you just used a main <div> container for your tooltip and placed all the other <div> elements inside it to create the pieces.

As for your question, it is possible to modify pseudo-elements in JavaScript, but it involves a lot of coding and seems excessive for the issue you're facing. You can check out the solution here

My suggestion would be to build your tooltip using <div>s and avoid all the unnecessary complexity.

Here's how you can modify your tooltip. Start by adding a .tooltip{...} class to the tooltip container with visibility: hidden or display: none depending on your preference and application needs.

If you go with visibility: hidden, you can toggle the property on click as desired:

CSS

.tooltip {
   visibility: hidden;
}

JavaScript

document.querySelector("tooltip").classList.add('hidden-tooltip');

To remove the class later on, you can use:

document.getElementById("tooltip").classList.remove('hidden-tooltip');

If you opt for using the display property instead of visibility, simply toggle between none, block, or flex based on your layout needs. Enjoy!

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

Tips for applying an active class to buttons using ng-click?

Here is the HTML code for the buttons. The taskfilter is the filter that controls how the buttons work when clicked and the class name is 'sel' <a class="clear-completed" ng-click="taskfilter = 1" ng-class="{'sel':enabled}"> &l ...

Add a custom Leaflet JS control button with personalized text and hover functionality

I successfully completed a control-button-leaflet tutorial and it worked for me. Now I have some additional requirements: Show some text when hovering over the button (similar to the zoom buttons) Change the button's color when hovering over it Abil ...

Resetting text in an input field using CSS

Here is the fiddle link for reference: http://jsfiddle.net/a765q/1/. I noticed that when I click the reset button, the text color changes to grey. Any ideas on how to fix this? ...

What is the process for generating a GET request for selected checkboxes and subsequently showcasing the data on an HTML webpage?

Currently working on an app project and need assistance with implementing a feature. I have successfully set up a POST method for the checkboxes that are checked, but I am unsure how to retrieve this data and display it on my HTML page using a GET method ...

Modifying an image's height and width attributes with jQuery and CSS on click action

I'm currently developing a basic gallery using HTML, CSS, and jQuery. The objective is to have a larger version of an image display in a frame with an overlay when the user clicks on it. While this works flawlessly for horizontally-oriented images, ve ...

Conundrum encountered: SIGTRAP causing Electron failure to initialize

Exploring Electron for creating desktop applications has been my recent endeavor. However, I encountered this pesky error: /home/me/dev/my-electron-app-2/node_modules/electron/dist/electron exited with signal SIGTRAP Since the path leads to a binary file, ...

Incorporating a classList.toggle into a snippet of code

button, p, h1, h2, h3, h4, h5, a{ /* Define specific elements to use "fantasy" font */ font-family: Tahoma; } #main_body{ margin: 0px auto; background-color: #dedede; } #top_body{ /* Remove margin for simplicity */ } #t ...

Is there a way to determine if my great-grandfather has a class attribute that includes a specific word?

Looking for some assistance with my HTML code snippet: <div class='one two three and etc.'> <div> <div> <div class='my_target'> </div> </div> ...

The common CSS technique using the before pseudo class is failing to address the issue of content disappearing behind the page

I've been struggling with implementing CSS code in my main stylesheet file. I followed the advice online to use the ::before pseudo class to align the height and margin with the header. However, even after making these adjustments, the content still a ...

Is it possible for 'will-change' to achieve the intended outcome when implemented using the Web Animations API?

Google recommends: Google suggests that if an animation may occur within the next 200ms [...] it's a good idea to use will-change on elements being animated. In most cases, any element in your app's current view that you plan to animate should ...

Enhancing gallery user experience with jquery to animate the opacity of active (hovered) thumbnails

I am attempting to create an animation that changes the opacity of thumbnails. By default, all thumbnails have an opacity of 0.8. When hovered over, the opacity should increase to 1 and then return to 0.8 when another thumbnail is hovered over. Here is th ...

Creating Projects Without a Build System in Sublime Text 3

I'm having trouble getting the sublime build system to function properly. When attempting to run my code, I receive a "No Build System" error message. I have already set the build system to Automatic under Tools->Build Systems and saved the file a ...

Vue - when multiple parents share a common child component

Is there a way in Vue.js for multiple parents to share the same child component? I am looking to have multiple delete buttons trigger a single modal with different content. For example: myfile.html: <table id="app" class="table table-striped table-s ...

The button text in Bootstrap 5 is black instead of white as shown in their demo

During the installation of Bootstrap 5, I encountered an issue where many of my buttons are displaying a black font instead of the expected white font as shown in the Bootstrap 5 Documentation For instance, the .btn-primary button on the official Bootstra ...

Substitute regular expressions with several occurrences by their respective capture groups

I am attempting to use JavaScript to extract only the link text from a string and remove the href tags. The expected behavior is as shown below: <a href='www.google.com'>google</a>, <a href='www.bing.com'>bing</a> ...

Tips for minimizing the influence of external code in Next.js

What steps can I take to minimize the impact of third-party code on my next.js app? I have incorporated Google Analytics and Google AdSense on my website, but it is causing performance issues. view this illustration _document.js import Document, { Html, ...

Ways to create a fading effect for a div container

As I delve into learning Rails, I've been immersed in a Rails web app where there is an enticing "Order" button that triggers a response saying: "Thank you for ordering". This message is displayed using the flash action. To enhance user experience, my ...

Is there a way to verify the textbox value in MVC without the need for clicking submit or performing a postback

Exploring MVC for the first time. I am working on a Registration Form with 10 textboxes for id, name, address, etc. I need to validate if the entered Id is already in the database and display the status without requiring the user to click a submit button. ...

AngularJS - Oops! Looks like we encountered an error: [$injector:modulerr]

I have a client-server application and I am facing an issue with this error message: "Uncaught Error: [$injector:modulerr]". Despite searching for solutions, none of them seem to be fixing the problem. Here is my client-side code: angular.module('m ...

The Android WebView display is consistently showing a blank white screen, failing to reflect CSS or HTML modifications, and exhibiting choppy animations

There seems to be a strange inconsistency when I make changes to CSS classes. Sometimes, after adding a down class name to a button using a touch event, the changes do not appear on the button or anywhere else on the page. It's frustrating how unpredi ...