Reputation: 321
There is a input with type number where the user can write a number. If the number is greater than 4 it will change the color of the input border to red.
I want to show the tooltip in the same situation, not on hover. Is it a way to do that?
<div className="tooltip">
<input
className="partial-quantity-input"
type="number"
min="0"
max="4"
value={quantity}
onChange={changeValue}
/>
<span className="tooltiptext">Exceeds original ordered quantity.</span>
</div>
css:
.partial-quantity-input {
background: rgb(255, 255, 255);
border-radius: 0px;
border: 1px solid rgb(255, 255, 255);
height: 40px;
width: 40px;
outline: none;
&:focus {
border: 1px solid rgb(201, 200, 200);
}
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield;
}
input:invalid {
outline: none;
border: 1px solid red;
}
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
bottom: 100%;
left: 50%;
margin-left: -60px;
width: 120px;
color: rgb(0, 0, 0);
text-align: center;
padding: 5px 0;
background: rgb(255, 255, 255);
border-radius: 3px;
border: 1px solid rgb(220, 220, 220);
height: 38px;
width: 252px;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
.tooltip:hover .tooltiptext {
visibility: visible;
}
as it is in the code, it shows the tooltip on hover (.tooltip:hover
).
I tried .tooltip:invalid
or .tooltip(input:invalid)
but did not work.
Any ideas?
Upvotes: 2
Views: 1881
Reputation: 3434
Using no combinator (better said: the Descendant Combinator) like this .element1 .element2
will make CSS look for any element that fits the .element2
-selector that is a descendant of .element1
. This means, .element2
can either be a direct or indirect child of .element1
.
For your case you should use a sibling combinator, ~
(General Sibling Combinator) or +
(Adjacent Sibling Combinator) to select .tooltiptext
for when input
can be selected using the :invalid
-selector.
.tooltip input:invalid ~ .tooltiptext {
/* Your CSS-rule to make `.tooltiptext` visible */
}
Just for this question I created a CSS tool-class .tooltipped
. Simply format your <input>
like the following to incorporate the tooltip (the classes in the brackets are options one of which needs to be chosen):
<div class="tooltipped (top | bottom | left | right)">
<input />
<div class="(on-invalid | always)">
<div>
<div>
(Place your content here)
</div>
</div>
</div>
</div>
The content you place in (Place your content here)
can be a simple message up to more HTML-code. When simply inserting a message, you might want to set white-space: pre
to retain its formatting, as it would otherwise try to keep the tooltip as narrow as possible.
Since the tooltip is placed using position: absolute
, you should make sure yourself that the tooltip to be shown has enough space to be read when being displayed.
Changing the side on which the tooltip should be shown is as easy as changing the directional class of .tooltipped
. This can even be done easily with JavaScript.
For example, you could change the directional-class when the phone might be too small to display the tooltip in its initial direction.
Obviously, you can make the input-element be of any type. If you want to invalidate it yourself (e.g. when :invalid
wouldn't trigger), you can give it the class .invalid
with JS for the same effect regarding this tooltip's features.
Here is an example showing basically all the available features:
/* For this example */
html, body {
margin: 0;
width: 100%;
height: 100%;
}
body {
display: grid;
grid-template-areas:
". ."
". .";
align-items: center;
justify-items: center;
}
input:invalid {
border-color: red;
outline-color: red;
background: pink;
}
/* Tool-class: Tooltip */
.tooltipped * {margin: 0}
.tooltipped {
--tt-bg: #3f3f3f;
display: flex;
align-items: center;
}
.tooltipped > div {
position: relative;
display: flex;
justify-content: center;
align-items: center;
visibility: hidden;
}
.tooltipped > div > div {
position: absolute;
display: flex;
align-items: center;
}
.tooltipped > div > div::before {
content: "";
border: 4px solid transparent;
}
.tooltipped > div > div > div {
padding: 0.1rem 0.4rem;
border-radius: 2px;
color: white;
background: var(--tt-bg);
}
/* Directional-classes */
.tooltipped.right > div > div {transform: translateX(50%)}
.tooltipped.right > div > div::before {border-right-color: var(--tt-bg)}
.tooltipped.left {flex-flow: row-reverse}
.tooltipped.left > div {justify-content: flex-end}
.tooltipped.left > div > div {flex-flow: row-reverse}
.tooltipped.left > div > div::before {border-left-color: var(--tt-bg)}
.tooltipped.top {flex-flow: column-reverse}
.tooltipped.top > div > div {
flex-flow: column-reverse;
transform: translateY(-50%);
}
.tooltipped.top > div > div::before {border-top-color: var(--tt-bg)}
.tooltipped.bottom {flex-flow: column}
.tooltipped.bottom > div > div {
flex-flow: column;
transform: translateY(50%);
}
.tooltipped.bottom > div > div::before {border-bottom-color: var(--tt-bg)}
/* "Listener"-classes */
.tooltipped input:invalid + .on-invalid,
.tooltipped input.invalid + .on-invalid {visibility: visible}
.tooltipped > .always {visibility: visible}
<div class="tooltipped top">
<input type="number" min="0" max="4"/>
<div class="on-invalid">
<div>
<div>
<p>I am a tooltip!</p>
</div>
</div>
</div>
</div>
<div class="tooltipped right">
<input type="number" min="0" max="4"/>
<div class="always">
<div>
<div>
<p>I am a tooltip!</p>
</div>
</div>
</div>
</div>
<div class="tooltipped bottom">
<input type="number" min="0" max="4"/>
<div class="on-invalid">
<div>
<div>
<p>I am a tooltip!</p>
</div>
</div>
</div>
</div>
<div class="tooltipped left">
<input type="number" min="0" max="4"/>
<div class="always">
<div>
<div>
<p>I am a tooltip!</p>
</div>
</div>
</div>
</div>
Upvotes: 2
Reputation: 2384
You can achieve the tooltip part using JavaScript
:
For example:
let input = document.getElementById("quantity-input");
let tooltip = document.getElementById("invalid_entry");
input.addEventListener("keyup", function(e){
if(e.currentTarget.value.length > 4){
tooltip.innerHTML = "Exceeded length of 4";
tooltip.style.display = "block";
input.style.border = "3px solid red";
}
else if(e.currentTarget.value.length <= 4) {
tooltip.innerHTML = "";
tooltip.style.display = "none";
input.style.borderColor = "1px solid black";
}
})
.partial-quantity-input {
background: rgb(255, 255, 255);
border-radius: 0px;
border: 1px solid rgb(255, 255, 255);
height: 40px;
width: 40px;
outline: none;
&:focus {
border: 1px solid rgb(201, 200, 200);
}
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield;
}
input:invalid {
outline: none;
border: 1px solid red;
}
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
bottom: 100%;
left: 50%;
margin-left: -60px;
width: 120px;
color: rgb(0, 0, 0);
text-align: center;
padding: 5px 0;
background: rgb(255, 255, 255);
border-radius: 3px;
border: 1px solid rgb(220, 220, 220);
height: 38px;
width: 252px;
/* Position the tooltip */
position: absolute;
z-index: 1;
}
.tooltip:hover .tooltiptext {
visibility: visible;
}
#invalid_entry {
display: none;
background: orange;
padding: 6px;
color: #fff;
position: absolute;
left: 20px;
top: 28px;
}
<div className="tooltip">
<span id="invalid_entry"></span>
<input
className="partial-quantity-input"
id="quantity-input"
type="number"
min="0"
max="4"
/>
<!-- <span className="tooltiptext">Exceeds original ordered quantity.</span> -->
</div>
Upvotes: 1