Tooltip nested in <label>, prevent 'mousedown' triggering input:active - javascript

I have a specific situation where we nest tooltip in <label> (which we use for to implement custom radio button design).
event.preventDefault() works fine with 'click' on the tooltip but fails on 'mousedown' where it triggers :active state of the hidden <input> field. Thus changing the styling of fake radio button.
I made a small example to demonstrate what is happening.
const $tooltipElement = $('.tooltip');
$tooltipElement.on('click', (event) => {
event.preventDefault();
})
label {
position: relative;
display: inline-block;
margin-right: 10px;
}
input {
opacity: 0;
left: 0;
position: absolute;
overflow: hidden;
pointer-events: none;
}
.box {
width: 15px;
height: 15px;
border-radius: 50%;
border: 1px solid gray;
display: inline-block;
cursor: pointer;
}
input:checked+.box {
background: blue;
}
input:active+.box {
background: red;
}
.text {
cursor: pointer;
}
.tooltip {
display: inline-block;
width: 8px;
height: 8px;
border: 2px solid red;
}
.tooltip:active {
background: gray;
}
.tooltip:active::before {
content: attr(data-content);
position: absolute;
width: 100px;
height: 80px;
background-color: #fff;
text-align: center;
top: 100%;
left: 50%;
transform: translateX(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>
<input type="radio" name="radio">
<span class="box"></span>
<span class="text">Option 1</span>
<span class="tooltip" data-content="Message 1" tab-index="0"></span>
</label>
<label>
<input type="radio" name="radio">
<span class="box"></span>
<span class="text">Option 2</span>
<span class="tooltip" data-content="Message 2" tab-index="0"></span>
</label>
This is how it looks when holding mousedown on tooltip. Radio circle, must remain the same, but it changes to red bg color...
jsFiddle here

How is this: instead of putting the tooltip in the label, put it in a span the wraps the label and tooltip (moving your label styles to this span):
const $tooltipElement = $('.tooltip');
$tooltipElement.on('click', (event) => {
event.preventDefault();
})
.wrapper {
position: relative;
display: inline-block;
margin-right: 10px;
}
input {
opacity: 0;
left: 0;
position: absolute;
overflow: hidden;
pointer-events: none;
}
.box {
width: 15px;
height: 15px;
border-radius: 50%;
border: 1px solid gray;
display: inline-block;
cursor: pointer;
}
input:checked+.box {
background: blue;
}
input:active+.box {
background: red;
}
.text {
cursor: pointer;
}
.tooltip {
display: inline-block;
width: 8px;
height: 8px;
border: 2px solid red;
}
.tooltip:active {
background: gray;
}
.tooltip:active::before {
content: attr(data-content);
position: absolute;
width: 100px;
height: 80px;
background-color: #fff;
text-align: center;
top: 100%;
left: 50%;
transform: translateX(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="wrapper">
<label>
<input type="radio" name="radio">
<span class="box"></span>
<span class="text">Option 1</span>
</label>
<span class="tooltip" data-content="Message 1" tab-index="0"></span>
</span>
<span class="wrapper">
<label>
<input type="radio" name="radio">
<span class="box"></span>
<span class="text">Option 2</span>
</label>
<span class="tooltip" data-content="Message 2" tab-index="0"></span>
</span>

Related

Active Toggle switch to change pricing

I built a page that has three payment plans. There is also a Toggle switch, to change between Monthly and Annually. I have the price set to ex. $19.99 for monthly and when I click the toggle button to switch to annually I want the price to change to $199.99. Here is the code I have so far. All HTML and CSS so now my JS isn't working for it. What's wrong?
function myFunction() {
var x = document.getElementsByClassName("switch");
if (x.innerHTML === "$19.99") {
x.innerHTML = "$199.99";
} else {
x.innerHTML = "$19.99";
}
}
input.cmn-toggle-round:checked+label:after {
margin-left: 32px;
}
.switch {
position: relative;
left: 47.5%;
}
.cmn-toggle {
position: absolute;
margin-left: -9999px;
visibility: hidden;
}
.cmn-toggle+label {
display: block;
position: relative;
cursor: pointer;
outline: none;
user-select: none;
}
input.cmn-toggle-round+label {
padding: 2px;
width: 50px;
height: 20px;
background-color: #dddddd;
border-radius: 60px;
}
input.cmn-toggle-round+label:before,
input.cmn-toggle-round+label:after {
display: block;
position: absolute;
top: 1px;
left: 1px;
bottom: 1px;
content: "";
}
input.cmn-toggle-round+label:before {
right: 1px;
background-color: #f1f1f1;
border-radius: 60px;
transition: background 0.4s;
}
input.cmn-toggle-round+label:after {
width: 20px;
background-color: #fff;
border-radius: 100%;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
transition: margin 0.4s;
}
input.cmn-toggle-round:checked+label:before {
background-image: Linear-Gradient( to left, hsl(236, 72%, 79%), hsl(237, 63%, 64%)
);
}
<div class="switch" onclick="myFunction()">
<input id="cmn-toggle-1" class="cmn-toggle cmn-toggle-round" type="checkbox" />
<label for="cmn-toggle-1"></label>
</div>
There are several problem with your code. First you compare against the innerHTML property which isn't initially set this can not work until you have a default value.
The next is that you want to set the wrapper containers innerHTML which will remove the button.
In the solution below I introduced an paragraph with an initialValue of 199.95 and then toggle on it.
Also I replaced the incline scripting and used instead an eventListener.
let inp = document.getElementById("cmn-toggle-1");
inp.addEventListener("click", myFunction);
function myFunction() {
var x = document.getElementById("par");
if(x.innerHTML === "$199.99"){
x.innerHTML = "$19.99";
}else{
x.innerHTML = "$199.99";
}
}
input.cmn-toggle-round:checked+label:after {
margin-left: 32px;
}
.switch {
position: relative;
left: 47.5%;
}
.cmn-toggle {
position: absolute;
margin-left: -9999px;
visibility: hidden;
}
.cmn-toggle+label {
display: block;
position: relative;
cursor: pointer;
outline: none;
user-select: none;
}
input.cmn-toggle-round+label {
padding: 2px;
width: 50px;
height: 20px;
background-color: #dddddd;
border-radius: 60px;
}
input.cmn-toggle-round+label:before,
input.cmn-toggle-round+label:after {
display: block;
position: absolute;
top: 1px;
left: 1px;
bottom: 1px;
content: "";
}
input.cmn-toggle-round+label:before {
right: 1px;
background-color: #f1f1f1;
border-radius: 60px;
transition: background 0.4s;
}
input.cmn-toggle-round+label:after {
width: 20px;
background-color: #fff;
border-radius: 100%;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
transition: margin 0.4s;
}
input.cmn-toggle-round:checked+label:before {
background-image: Linear-Gradient( to left, hsl(236, 72%, 79%), hsl(237, 63%, 64%));
}
<div class="switch">
<input id="cmn-toggle-1" class="cmn-toggle cmn-toggle-round" type="checkbox" />
<label for="cmn-toggle-1"></label>
<p id="par">$199.99</p>
</div>
Having just read the comment about using the code to manipulate prices for several elements you need a different approach as using an ID will no longer work - ID attributes must be unique so unless you get tricky with numerically incremented indices and the like ( messy ) you can inspect the target attribute of any click event ( or other type ) and use parent/child/sibling selectors to identify and manipulate nodes of interest.
The HTML below was slightly modified by adding dataset attributes and ignoring any ID attributes present. The CSS was hastily fudged to facilitate the display.... but I think it shows how you might do it.
An event listener is assigned to each parent DIV (.switch) and the currentTarget property of the event is used to find the label which actually receives the click. Using the combination of parentNode and querySelector we can identify the nodes we need to make the logic work
document.querySelectorAll('div.switch').forEach( div=>{
div.addEventListener('click',e=>{
if( e.target === e.target.parentNode.lastElementChild ) {
let span=e.target.parentNode.querySelector('span');
document.documentElement.style.setProperty('--currency','$')
span.dataset.price=e.currentTarget.dataset.state == 1 ? e.currentTarget.dataset.annual : e.currentTarget.dataset.month;
span.dataset.period=e.currentTarget.dataset.state == 1 ? 'Monthly:' : 'Annually:';
span.dataset.currency=document.documentElement.style.getPropertyValue('--currency');
e.currentTarget.dataset.state = 1 - Number( e.currentTarget.dataset.state );
}
})
})
input.cmn-toggle-round:checked + label:after {
margin-left: 32px;
}
.switch {
--left:47.5%;
position: relative;
left: var(--left);
margin:1rem 0 1.5rem 0;
width:calc(80% - var(--left));
}
.cmn-toggle {
position: absolute;
margin-left: -9999px;
visibility: hidden;
}
.cmn-toggle+label {
display: block;
position: relative;
cursor: pointer;
outline: none;
user-select: none;
}
input.cmn-toggle-round+label {
padding: 2px;
width: 50px;
height: 20px;
background-color: #dddddd;
border-radius: 60px;
}
input.cmn-toggle-round+label:before,
input.cmn-toggle-round+label:after {
display: block;
position: absolute;
top: 1px;
left: 1px;
bottom: 1px;
content: "";
}
input.cmn-toggle-round+label:before {
right: 1px;
background-color: #f1f1f1;
border-radius: 60px;
transition: background 0.4s;
}
input.cmn-toggle-round + label:after {
width: 20px;
background-color: #fff;
border-radius: 100%;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
transition: margin 0.4s;
}
input.cmn-toggle-round:checked + label:before {
background-image: Linear-Gradient( to left, hsl(236, 72%, 79%), hsl(237, 63%, 64%) );
}
span:after{
display:inline-block;
float:right;
clear:none;
margin:0;
content:attr(data-period)' 'attr(data-currency)attr(data-price)!important;
}
<div class='switch' data-state=0 data-month='199.99' data-annual='19.99'>
<span></span>
<input id='cmn-toggle-1' class='cmn-toggle cmn-toggle-round' type='checkbox' />
<label for='cmn-toggle-1'></label>
</div>
<div class='switch' data-state=0 data-month='259.99' data-annual='23.99'>
<span></span>
<input id='cmn-toggle-2' class='cmn-toggle cmn-toggle-round' type='checkbox' />
<label for='cmn-toggle-2'></label>
</div>
<div class='switch' data-state=0 data-month='150.00' data-annual='75.00'>
<span></span>
<input id='cmn-toggle-3' class='cmn-toggle cmn-toggle-round' type='checkbox' />
<label for='cmn-toggle-3'></label>
</div>
<div class='switch' data-state=0 data-month='652.50' data-annual='480.50'>
<span></span>
<input id='cmn-toggle-4' class='cmn-toggle cmn-toggle-round' type='checkbox' />
<label for='cmn-toggle-4'></label>
</div>
<div class='switch' data-state=0 data-month='40.00' data-annual='19.99'>
<span></span>
<input id='cmn-toggle-5' class='cmn-toggle cmn-toggle-round' type='checkbox' />
<label for='cmn-toggle-5'></label>
</div>
<div class='switch' data-state=0 data-month='300.00' data-annual='14.99'>
<span></span>
<input id='cmn-toggle-6' class='cmn-toggle cmn-toggle-round' type='checkbox' />
<label for='cmn-toggle-6'></label>
</div>

Show a box and do not fade it as long as the mouse is on it

Show a box and its axis as long as the mouse is on it
Hi
The box is displayed when the input key is pressed. The problem is that when I try to click on the box numbers when the box is displayed, the box is hidden.
Friends, how can I solve this problem?
function show1() {
document.getElementById("box1").style.display="block"
}
function hide() {
document.getElementById("box1").style.display="none"
}
function volcal(a) {
document.querySelector("#number").value=a
}
#number {
opacity: 30%;
padding: 3px;
}
#number:hover {
opacity: 100%;
border-color: #ff0000;
border-width: 1px;
color: #0064ff;
}
#box1 {
display: none;
width: 30.5%;
margin-right: 13px;
padding: 3px;
text-align: center;
border-style: solid;
border-color: #3b3b3b;
}
<input id="number" onblur="hide()" onfocus="show1()" min="0" >
<span id="box1" style="display: non;" onmouseout="hide()" onmouseover="show1()"> value =
<span class="me1" onclick="volcal(this.innerHTML)">
1,000
</span>
<span class="wbb3" > | </span>
<span class="me1" onclick="volcal(this.innerHTML)">
10,000
</span>
</span>
Instead of using mouse out event to hide element you can use a click on a transparent background div that fill the entire screen, so when you click outside the box will hide.
function show1() {
document.getElementById("box1").style.display = "block";
document.getElementById("back-layer1").style.display = "block";
}
function hide() {
document.getElementById("box1").style.display = "none";
document.getElementById("back-layer1").style.display = "none";
}
function volcal(a) {
document.querySelector("#number").value = a;
}
#number {
opacity: 30%;
padding: 3px;
position: relative;
z-index: 100;
}
#number:hover {
opacity: 100%;
border-color: #ff0000;
border-width: 1px;
color: #0064ff;
}
#box1 {
display: none;
width: 30.5%;
margin-right: 13px;
padding: 3px;
text-align: center;
border-style: solid;
border-color: #3b3b3b;
z-index: 100;
position: relative;
}
#back-layer1 {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: transparent; /* change to red to see the behavior */
z-index: 10;
}
<div>
<div id="back-layer1" style="display: none" onclick="hide()"></div>
<input id="number" onfocus="show1()" min="0" />
<span id="box1" style="display: non" onmouseover="show1()">
value =
<span class="me1" onclick="volcal(this.innerHTML)"> 1,000 </span>
<span class="wbb3"> | </span>
<span class="me1" onclick="volcal(this.innerHTML)"> 10,000 </span>
</span>
</div>

How to move slider of slider-like checkbox to one of its labels when clicking on them?

I need to make that switch slider move to the word user has clicked on (medium or large). I don't know if I can track movement of switch slider with JavaScript or maybe it is possible to do with css. For now, I have only created simple toggle switcher with changing color. The problem is that slider was customised a lot with :before, :checked, input and etc so I don't realise even where to start to make it happen.
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.row-inputs-radio {
display: flex;
justify-content: space-between;
}
.item-size {
margin-left: 10px;
}
.item-size-eg {
font-size: 15px;
color: rgb(155, 154, 154);
}
.continue-btn button {
outline: none;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 10px;
margin-top: 15px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: -74px;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
width: 187px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: -3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border: 1px solid grey;
}
input:checked + .slider {
background-color: #13985C;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(120px);
-ms-transform: translateX(120px);
transform: translateX(162px);
}
<div class="column-input">
<div class="row-inputs row-inputs-radio">
<div class="row-input">
<div class="item-size"><bold>Medium</bold></div>
</div>
<div class="row-input">
<label class="switch">
<input type="checkbox" checked />
<span class="slider round"></span>
</label>
</div>
<div class="row-input">
<div class="item-size"><bold>Large</bold></div>
</div>
</div>
Let's go step by step:
We get the medium, large, and input elements
Add onclick eventListeners to them for toggling
Add cursor: pointer to show they're clickable
var medium = document.querySelector('.medium'),
large = document.querySelector('.large'),
slider = document.querySelector('.switch input');;
medium.onclick = function() {
slider.checked = false;
}
large.onclick = function() {
slider.checked = true;
}
.medium, .large {
cursor: pointer;
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.row-inputs-radio {
display: flex;
justify-content: space-between;
}
.item-size {
margin-left: 10px;
}
.item-size-eg {
font-size: 15px;
color: rgb(155, 154, 154);
}
.continue-btn button {
outline: none;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 10px;
margin-top: 15px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: -74px;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
width: 187px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: -3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border: 1px solid grey;
}
input:checked+.slider {
background-color: #13985C;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(120px);
-ms-transform: translateX(120px);
transform: translateX(162px);
}
<div class="column-input">
<div class="row-inputs row-inputs-radio">
<div class="row-input">
<div class="item-size medium">
<bold>Medium</bold>
</div>
</div>
<div class="row-input">
<label class="switch">
<input type="checkbox" checked />
<span class="slider round"></span>
</label>
</div>
<div class="row-input">
<div class="item-size large">
<bold>Large</bold>
</div>
</div>
</div>
Using addEventListener()
The wanted behavior can be achieved by adding an event-listener to the labels to (un-)check the checkbox.
We can use Event delegation to only add one event-listener to the parent. We can use a boolean that tells us if the clicked label is the "on"-label (meaning, the label that should check the checkbox).
This boolean can immediately be used as the value the .checked-attribute should now have. Quick explanation:
Is the label the "on"-label? If yes, do check
Is the label the "on"-label? If no, do not check
In pseudo-code, it would look like this:
checkbox.checked = isOnLabel
We can check if the clicked label is the "on"-label by looking if the .row-input-div it is inside of is the last one.
Note:
Only adding a click-listener to an element which isn't clickable by default doesn't make it accessible.
To make an element accessible clickable, one would have to:
Add all the appropriate listeners (click-listener, key-listener; specific elements listen for specific keys, e.g. a button for 'space', an anchor for 'enter', a radio-group for the arrow-keys)
Make the element ARIA-conform (use semantically meaningful HTML, e.g. specific HTML-elements, aria-role, aria-label)
This can be quite a lot of work, so unless there is a good reason to create an element from new, one should stick to what is currently given in the HTML-specification (though it is easier to read up on HTML-elements on MDN).
Here is the snippet to show the result:
Note: The code also works for multiple .column-inputs.
for (let ci of document.querySelectorAll('.column-input')) {
ci.addEventListener('click', evt => {
let ri = evt.target.closest('.row-input'); // Get the '.row-input'-div
if (ri.querySelector('.item-size')) { // If `ri` contains '.item-size' / a label, continue
// '!ri.nextElementSibling' is true if `ri` is the last element
ci.querySelector('input').checked = !ri.nextElementSibling;
}
});
}
.slider.round {border-radius: 34px}
.slider.round:before {border-radius: 50%}
.row-inputs-radio {
display: flex;
justify-content: space-between;
}
.item-size {margin-left: 10px}
.item-size-eg {
font-size: 15px;
color: rgb(155, 154, 154);
}
.continue-btn button {outline: none}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 10px;
margin-top: 15px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: -74px;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
width: 187px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: -3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border: 1px solid grey;
}
input:focus + .slider {box-shadow: 0 0 1px #2196F3}
input:checked + .slider {background-color: #13985C}
input:checked + .slider:before {
-webkit-transform: translateX(120px);
-ms-transform: translateX(120px);
transform: translateX(162px);
}
<div class="column-input">
<div class="row-inputs row-inputs-radio">
<div class="row-input">
<div class="item-size"><bold>Medium</bold></div>
</div>
<div class="row-input">
<label class="switch">
<input type="checkbox" checked />
<span class="slider round"></span>
</label>
</div>
<div class="row-input">
<div class="item-size"><bold>Large</bold></div>
</div>
</div>
</div>
<div class="column-input">
<div class="row-inputs row-inputs-radio">
<div class="row-input">
<div class="item-size"><bold>Mayo</bold></div>
</div>
<div class="row-input">
<label class="switch">
<input type="checkbox" checked />
<span class="slider round"></span>
</label>
</div>
<div class="row-input">
<div class="item-size"><bold>Ketchup</bold></div>
</div>
</div>
</div>
HTML/CSS only
One could also make a slider-like element using radio-groups, where the radio-group would consist of two elements: "on" and "off".
In combination with labels, the user (sighted or tool-assisted) knows what both options of the sliders are, and can select one accordingly, either by using the mouse or by using the keyboard.
You can try it yourself! Tab to the radio-group, and press the arrow-keys.
Associating a label with an input-element has the following advantages:
It correctly labels its input-element for tools (e.g. screen-readers)
Clicking a label behaves the same way as clicking its input-element itself
(the effect we achieved before using addEventListener() is implemented for associated labels by default)
It doesn't require any JavaScript
For graphics, instead of misusing an HTML-element, I used SVG in combination with CSS.
Having multiple input-elements has the advantage of being able to give each one an individual value. This might be useful for submitting a <form>, so that the back-end would have an easier time figuring out what the values mean (e.g. a radio-groups' "Mayo" / "Ketchup" versus a checkbox' "Mayo or Ketchup" = (true | false)). This also makes maintenance easier, and the back-end wouldn't have to look into front-end code to understand the meaning of a value.
Notice the aria-hidden="true"-attribute for the <label>s inside the <svg>. That tells the browser to ignore those tags for building the Accessibility Tree, meaning only the labels with the labelling content will be associated with their input-elements.
As far as I know, this should be one way to make the slider-mechanic you want fully accessible, for both mouse- and keyboard-users, as well as sighted and tool-assisted users.
/* OPTIONAL
*
* HTML-element can be used without JS.
* However, one would need to manually add
* the radio-names in these places:
* - as <input>'s names
* - prepend <input>'s id
* - prepend <label>'s for
*/
for (var rs of document.querySelectorAll('.radio-slider')) {
var rsName = rs.getAttribute('data-name') || 'broken';
for (var rsInput of rs.querySelectorAll('input')) {
rsInput.id = rsName + rsInput.id;
rsInput.name = rsName;
}
for (var rsLabel of rs.querySelectorAll('label')) {
rsLabel.setAttribute('for', rsName + rsLabel.getAttribute('for'));
}
}
/* Tool-classes (TC); DO NOT CHANGE */
/* TC: '.sr-only' */
.sr-only {
position: absolute;
margin: -1px;
padding: 0;
clip: rect(0,0,0,0);
width: 1px;
height: 1px;
border: 0;
overflow: hidden;
}
/* TC: '.radio-slider' */
.radio-slider svg { /* Dimension of 8:5 */
width: 2rem;
height: 1.25rem;
}
.radio-slider > div {display: flex}
.radio-slider input:focus-visible ~ div {outline: auto}
.radio-slider input:focus-visible ~ div svg rect {fill: #2196F3}
.radio-slider circle,
.radio-slider rect {transition: 0.5s}
.radio-slider foreignObject > label {
width: 100%;
height: 18px;
display: block;
}
.radio-slider .on:checked ~ div svg foreignObject:last-child {display: none}
.radio-slider .on:checked ~ div svg rect {fill: #13985C}
.radio-slider .on:checked ~ div svg circle {transform: translateX(calc(2rem - 16px))}
<div class="radio-slider" data-name="radio1">
<input id="-off" class="sr-only off" type="radio">
<input id="-on" class="sr-only on" type="radio">
<div>
<label for="-off">Medium</label>
<svg viewBox="0 0 32 20" xmlns="xmlns=http://www.w3.org/1999/xhtml" stroke="black" fill="lightgray" stroke-width="0.5">
<rect x="4" y="4" rx="4" width="24" height="8" />
<circle cx="8" cy="8" r="6" fill="white" />
<foreignObject width="100%" height="100%"><label for="-off" aria-hidden="true"></label></foreignObject>
<foreignObject width="100%" height="100%"><label for="-on" aria-hidden="true"></label></foreignObject>
</svg>
<label for="-on">Large</label>
</div>
</div>
<div class="radio-slider" data-name="radio2">
<input id="-off" class="sr-only off" type="radio">
<input id="-on" class="sr-only on" type="radio">
<div>
<label for="-off">Mayo</label>
<svg viewBox="0 0 32 20" xmlns="xmlns=http://www.w3.org/1999/xhtml" stroke="black" fill="lightgray" stroke-width="0.5">
<rect x="4" y="4" rx="4" width="24" height="8" />
<circle cx="8" cy="8" r="6" fill="white" />
<foreignObject width="100%" height="100%"><label for="-off"></label></foreignObject>
<foreignObject width="100%" height="100%"><label for="-on"></label></foreignObject>
</svg>
<label for="-on">Ketchup</label>
</div>
</div>
In my example, I did not assign a unique class to each side. And so I used the forEach() method.
let select = document.querySelectorAll('.row-input .item-size');
let checked_pos = document.querySelector('.row-input .switch input[type="checkbox"]');
Array.from(select).forEach(function(selectCurrent, index) {
selectCurrent.onclick = function() {
if (index == 0) {
checked_pos.checked = false;
}
if (index == 1) {
checked_pos.checked = true;
}
}
});
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.row-inputs-radio {
display: flex;
justify-content: space-between;
}
.item-size {
margin-left: 10px;
}
.item-size-eg {
font-size: 15px;
color: rgb(155, 154, 154);
}
.continue-btn button {
outline: none;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 10px;
margin-top: 15px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: -74px;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
width: 187px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: -3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border: 1px solid grey;
}
input:checked + .slider {
background-color: #13985C;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(120px);
-ms-transform: translateX(120px);
transform: translateX(162px);
}
<div class="column-input">
<div class="row-inputs row-inputs-radio">
<div class="row-input">
<div class="item-size"><bold>Medium</bold></div>
</div>
<div class="row-input">
<label class="switch">
<input type="checkbox" checked/>
<span class="slider round"></span>
</label>
</div>
<div class="row-input">
<div class="item-size"><bold>Large</bold></div>
</div>
</div>

How to show tooltip On click event Using JavaScript

How can I show a tooltip by clicking on a button with JavaScript ?
Here is my code:
HTML
<div class="tooltip">Hover over me
<div class="tooltiptext">
<button>click me</button>
<span >Tooltip text
</span>
</div>
</div>
CSS
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
.tooltip:hover .tooltiptext {
visibility: visible;
}
The tooltip is showing while doing hover. But I want to show tooltip while using on click event using only JavaScript how will I do that. Please help me.
I whipped up a toggle using ES5. I wasn't sure if you were using a transpiler. I made a couple of tweaks to your CSS.
Depending on your implementation, this should be refactored to use event delegation.
var tooltip = document.querySelector('.tooltip')
tooltip.addEventListener('click', function() {
if (this.classList.contains('active')) {
this.classList.remove('active');
} else {
this.classList.add('active');
}
});
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
cursor: pointer;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
.tooltip.active .tooltiptext {
visibility: visible;
}
<div class="tooltip">Hover over me
<div class="tooltiptext">
<button>click me</button>
<span >Tooltip text
</span>
</div>
</div>
Try the following setup:
html
<button id="button1">click me</button>
<div class="tooltiptext">
<span >Tooltip text</span>
</div>
css
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
js
var button1 = document.querySelectorAll('#button1');
button1.onclick = buttonClicked;
function buttonClicked(){
var tooltip = document.querySelectorAll('.tooltiptext');
tooltip.style.visibility = 'visible';
}
I guess you want something like this. When you click on "hover me" it shows your tooltip and you can close it with X
<div onmousedown="show()" class="tooltip">
Hover over me
<div id="tooltip" onmouseup="hide()" class="tooltiptext">
<span>Tooltip text </span><span class="close">X</span>
</div>
</div>
CSS:
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip:hover {
cursor: pointer;
}
.close {
color: red;
}
.close:hover {
cursor: pointer;
}
.tooltip .tooltiptext {
display: none;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
.block {
display: block !important;
}
JavaScript:
function hide() {
document.getElementById("tooltip").classList.remove("block");
}
function show() {
document.getElementById("tooltip").classList.add("block");
}
Another simple way of achieving this is by using the event listener to change the display style from none to block and vice versa.
For it to work properly is important to add the style attribute to the tooltip element like so: <tooltip id='tooltip' style='display:none'>
const btn = document.getElementById('btn'),
tooltip = document.getElementById('tooltip');
btn.addEventListener('click', () => {
if (tooltip.style.display === "none") {
tooltip.style.display = "block";
}
else{
tooltip.style.display = "none";
}
})
#tooltip {
position: absolute;
margin-top:5px;
width: 80px;
background-color: rgb(0, 0, 0, 0.7);
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
}
<div style='position:relative'>
<button id='btn' style='cursor:pointer'>Try me</button>
<tooltip id='tooltip' style='display:none'>
Some text here
</tooltip>
<div>
<div class="tooltip">
Hover over me
<div class="tooltiptext">
<button>click me</button>
<span >Tooltip text
</span>
</div>
</div>
Try using focus
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
.tooltip a{ color: inherit; text-decoration: none; }
.tooltip a:focus+.tooltiptext {
visibility: visible;
}

how to show tick mark and an overlay on image while clicking an image, but when i click other image it should hide and display the same on new image?

i want the image to be overlay-ed with any color and give a tick mark on it(As it is selected) allowing only one image at a time. while clicking other image it should hide the previous one and show tick and overlay on new image.
<div class="grid-two imageandtext">
<figure>
<img src="assets/images/painting.jpg" class="img-thumbnail">
<div class="caption">
<p>Painting</p>
</div>
<div class="imageandtext image_grid">
<img src="assets/images/photography.jpg" class="img-thumbnail" >
<div class="caption1">
<p>Photography</p>
</div></div>
</figure>
</div>
it should display like below image
now it is working like this
https://jsfiddle.net/liza_susan/L8jyum77/
Here is a start, using a pseudo element for the cover, a label and an input of type radio to take care of the selection.
I wrapped the image in a label, and when clicked, it simply checks the input.
In the CSS, when an input is checked, the .image_grid input:checked + .caption::after rule apply the properties to cover and show the check mark.
Updated fiddle
.caption {
position: absolute;
top: 0;
left: 5px; /* changed to match image_grid padding */
height: 100%;
width: calc(100% - 5px); /* changed to match image_grid padding */
padding: 0 10px;
box-sizing: border-box;
pointer-events: none;
}
.caption p {
display: inline-block;
padding: 10px;
color: #fff;
background: rgba(0,0,0,0.5);
font-family: 'Myriad Pro regular';
font-size: 15.31px;
}
.imageandtext {
position: relative;
}
.image_grid {
display: inline-block;
padding-left: 5px;
}
.image_grid img { /* added rule */
display: block;
}
.image_grid input {
display: none;
}
.image_grid input:checked + .caption {
background: rgba(0,0,0,0.5);
}
.image_grid input:checked + .caption::after {
content: '✔';
position: absolute;
top: 50%; left: 50%;
width: 70px; height: 70px;
transform: translate(-50%,-50%);
color: white;
font-size: 60px;
line-height: 80px;
text-align: center;
border: 2px solid white;
border-radius: 50%;
}
<div class="grid-two imageandtext">
<div class="imageandtext image_grid">
<label for="selimg1">
<img src="http://yaitisme.com/images/getImage.jpg" class="img-thumbnail">
</label>
<input type="radio" name="selimg" id="selimg1">
<div class="caption">
<p>Painting</p>
</div>
</div>
<div class="imageandtext image_grid">
<label for="selimg2">
<img src="http://yaitisme.com/images/getImage.jpg" class="img-thumbnail">
</label>
<input type="radio" name="selimg" id="selimg2">
<div class="caption">
<p>Photography</p>
</div>
</div>
</div>
Based on a comment, here is a version where the caption is positioned inside the label, as a span (as label can only have inline element as children).
With this one doesn't need unique id on the input and can drop the for attribute, and no need to compensate for any padding and/or margin set on the image_grid.
Updated fiddle
Stack snippet
.caption {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
padding: 0 10px;
box-sizing: border-box;
pointer-events: none;
}
.caption span {
display: inline-block;
padding: 10px;
color: #fff;
background: rgba(0,0,0,0.5);
font-family: 'Myriad Pro regular';
font-size: 15.31px;
}
.image_grid {
display: inline-block;
padding-left: 25px;
}
.image_grid label {
position: relative;
display: inline-block;
}
.image_grid img {
display: block;
}
.image_grid input {
display: none;
}
.image_grid input:checked + .caption {
background: rgba(0,0,0,0.5);
}
.image_grid input:checked + .caption::after {
content: '✔';
position: absolute;
top: 50%; left: 50%;
width: 70px; height: 70px;
transform: translate(-50%,-50%);
color: white;
font-size: 60px;
line-height: 80px;
text-align: center;
border: 2px solid white;
border-radius: 50%;
}
<div class="grid-two imageandtext">
<div class="imageandtext image_grid">
<label>
<img src="http://yaitisme.com/images/getImage.jpg" class="img-thumbnail">
<input type="radio" name="selimg">
<span class="caption">
<span>Painting</span>
</span>
</label>
</div>
<div class="imageandtext image_grid">
<label>
<img src="http://yaitisme.com/images/getImage.jpg" class="img-thumbnail">
<input type="radio" name="selimg">
<span class="caption">
<span>Painting</span>
</span>
</label>
</div>
</div>
How about adding an image when someone hovers over it.
i.e.
.image-thumbnail:hover {
background-image: <path to image>;
background-repeat: no-repeat;
}
How about this JQuery function:
$('.image_grid').click(function() {
$('.image_grid img:nth-of-type(2)').hide();
$(this).children('img:nth-of-type(2)').show();
});
$('.image_grid').click(function() {
$('.image_grid img:nth-of-type(2)').hide();
$(this).children('img:nth-of-type(2)').show();
});
.grid-two {
width: 50%;
display: inline;
}
.caption1 {
position: absolute;
top: -51px;
left: 11px;
width: 100%;
color: #000;
font-family: Myriad Pro regular;
font-size: 15.31px;
}
.imageandtext {
position: relative;
}
.image_grid {
display: inline;
padding-left: 5px;
}
.absolute {
border: 1px solid black;
position: absolute;
left: 0px;
display: none;
width: 50%;
margin: 25%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="grid-two imageandtext">
<figure>
<div class="imageandtext image_grid">
<img src="http://yaitisme.com/images/getImage.jpg" class="img-thumbnail">
<div class="caption1">
<p>Painting</p>
</div>
<img src="https://i.stack.imgur.com/Kg1Do.png" class="absolute">
</div>
<div class="imageandtext image_grid">
<img src="http://yaitisme.com/images/getImage.jpg" class="img-thumbnail">
<div class="caption1">
<p>Photography</p>
</div>
<img src="https://i.stack.imgur.com/Kg1Do.png" class="absolute">
</div>
</figure>
</div>
JSFiddle

Categories