So, in my bootstrap 5 modal, I have a range slider. I added a tooltip to my three dynamic range sliders. After i add them, the tooltips overflow on the right side ( displaying incorrectly ). I attempted to make it on absolute positions, but it isn't working.
I want my tooltip to behave similarly to a standard range slider tooltip. I attempted to fix it, but because it is dynamic, those three range slider tooltips are showing the other right side of each range slider.
My code -
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link href='https://unpkg.com/[email protected]/css/boxicons.min.css' rel='stylesheet'>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700;800;900&display=swap');
.middle {
position: relative;
width: 100%;
max-width: 500px;
}
.slider {
position: relative;
z-index: 1;
height: var(--2, 8px);
}
.slider > .track {
position: absolute;
z-index: 1;
left: 0;
right: 0;
top: 0;
bottom: 0;
border-radius: 5px;
background-color: #E5E7EB;
}
.slider > .range {
position: absolute;
z-index: 2;
left: 25%;
right: 25%;
top: 0;
bottom: 0;
border-radius: 5px;
background-color: #1C64F2;
}
.slider > .thumb {
position: absolute;
z-index: 3;
width: 22px;
height: 22px;
background-color: #FFFFFF;
border-radius: 50%;
box-shadow: 0 0 0 0 rgba(98,0,238,.1);
transition: box-shadow .3s ease-in-out;
stroke-width: 1px;
stroke: var(--gray-200, #E5E7EB);
filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.08));
}
.slider > .thumb.left {
left: 25%;
transform: translate(-15px, -10px);
}
.slider > .thumb.right {
right: 25%;
transform: translate(15px, -10px);
}
input[type=range] {
position: absolute;
pointer-events: none;
-webkit-appearance: none;
z-index: 2;
height: 10px;
width: 100%;
opacity: 0;
}
input[type=range]::-webkit-slider-thumb {
pointer-events: all;
width: 22px;
height: 22px;
border-radius: 0;
border: 0 none;
background-color: red;
-webkit-appearance: none;
}
.tooltip {
position: absolute;
display: none;
background-color: #1c64f2;
color: #ffffff;
padding: var(--05, 2px) var(--2, 8px);
border-radius: 5px;
font-size: 12px;
white-space: nowrap;
opacity: 1;
top: -40px !important;
}
.modal-dialog {
max-width: 720px;
padding: 4px;
}
/* Max Result Start */
.max-result {
margin-top: 16px;
}
.max-result label {
color: #000;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: 150%;
margin-bottom: 12px;
}
.max-result .form-control {
box-shadow: none;
background-color: #F9FAFB;
border-color: #D1D5DB;
border-radius: 8px;
}
.max-result .form-control::placeholder {
color: #6B7280;
}
.price-range-section {
border-bottom: 1px solid #E5E7EB;
padding-bottom: 16px;
}
.price-range-section label:first-child {
color: #000;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: 150%;
margin-bottom: 26px;
}
.modal-body .price-range-section:nth-child(2) {
margin-top: 16px;
}
.modal-body-pad {
padding-top: 4px;
padding-bottom: 8px;
}
</style>
</head>
<body>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop">
Launch static backdrop modal
</button>
<!-- Modal -->
<div class="modal fade filter-modal" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header range-modal-header">
<h1 class="modal-title fs-5" id="staticBackdropLabel">Filters</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body modal-body-pad">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" id="blockA-tab" data-bs-toggle="tab" href="#blockA">Basic</a>
</li>
<li class="nav-item">
<a class="nav-link" id="blockB-tab" data-bs-toggle="tab" href="#blockB">Advanced</a>
</li>
</ul>
<div class="tab-content mt-2">
<div class="tab-pane fade show active" id="blockA">
<div class="container">
<div class="row">
<div class="col-sm-4">
<div class="price-range-section">
<label for="Price Range">Price Range</label>
<div class="middle">
<div class="multi-range-slider">
<input type="range" id="price-min-slider" min="0" max="100" value="25">
<input type="range" id="price-max-slider" min="0" max="100" value="75">
<div class="slider">
<div class="track"></div>
<div class="range"></div>
<div class="thumb left"></div>
<div class="thumb right"></div>
</div>
<!-- Tooltips -->
<div class="tooltip" id="tooltip-left"></div>
<div class="tooltip" id="tooltip-right"></div>
</div>
</div>
</div>
<div class="price-range-section">
<label for="Delivery Range">Delivery Time (Days)</label>
<div class="middle">
<div class="multi-range-slider multi-range-slider2">
<input type="range" id="min-delivery-slider" min="0" max="100" value="25">
<input type="range" id="max-delivery-slider" min="0" max="100" value="75">
<div class="slider">
<div class="track"></div>
<div class="range"></div>
<div class="thumb left"></div>
<div class="thumb right"></div>
</div>
<!-- Tooltips -->
<div class="tooltip" id="tooltip-left2"></div>
<div class="tooltip" id="tooltip-right2"></div>
</div>
</div>
</div>
<div class="price-range-section mt-3">
<label for="Bid Range">Bid Count</label>
<div class="middle">
<div class="multi-range-slider multi-range-slider3">
<input type="range" id="min-bid-slider" min="0" max="100" value="25">
<input type="range" id="max-bid-slider" min="0" max="100" value="75">
<div class="slider">
<div class="track"></div>
<div class="range"></div>
<div class="thumb left"></div>
<div class="thumb right"></div>
</div>
<!-- Tooltips -->
<div class="tooltip" id="tooltip-left3"></div>
<div class="tooltip" id="tooltip-right3"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
//Range Price Slider Script Start / Price slider
var PriceMinSlider = document.getElementById('price-min-slider');
var PriceMaxSlider = document.getElementById('price-max-slider');
var thumbLeft = document.querySelector('.slider > .thumb.left');
var thumbRight = document.querySelector('.slider > .thumb.right');
var range = document.querySelector('.slider > .range');
var tooltipLeft = document.getElementById('tooltip-left');
var tooltipRight = document.getElementById('tooltip-right');
function setLeftValue() {
var _this = PriceMinSlider,
min = parseInt(_this.min),
max = parseInt(_this.max);
_this.value = Math.min(
parseInt(_this.value),
parseInt(PriceMaxSlider.value) - 1
);
var percent = ((_this.value - min) / (max - min)) * 100;
thumbLeft.style.left = percent + '%';
range.style.left = percent + '%';
updateTooltipPosition();
}
setLeftValue();
function setRightValue() {
var _this = PriceMaxSlider,
min = parseInt(_this.min),
max = parseInt(_this.max);
_this.value = Math.max(
parseInt(_this.value),
parseInt(PriceMinSlider.value) + 1
);
var percent = ((_this.value - min) / (max - min)) * 100;
thumbRight.style.right = 100 - percent + '%';
range.style.right = 100 - percent + '%';
updateTooltipPosition();
}
setRightValue();
function updateTooltipPosition() {
var thumbLeftPosition = thumbLeft.getBoundingClientRect();
var thumbRightPosition = thumbRight.getBoundingClientRect();
tooltipLeft.style.display = 'block';
tooltipLeft.style.left = thumbLeftPosition.left + 'px';
tooltipLeft.style.top = thumbLeftPosition.bottom + 5 + 'px';
tooltipLeft.innerHTML = PriceMinSlider.value;
tooltipRight.style.display = 'block';
tooltipRight.style.left = thumbRightPosition.left + 'px';
tooltipRight.style.top = thumbRightPosition.bottom + 5 + 'px';
tooltipRight.innerHTML = PriceMaxSlider.value;
}
PriceMinSlider.addEventListener('input', setLeftValue);
PriceMaxSlider.addEventListener('input', setRightValue);
PriceMinSlider.addEventListener('mousedown', function () {
thumbLeft.classList.add('active');
});
PriceMinSlider.addEventListener('mouseup', function () {
thumbLeft.classList.remove('active');
});
PriceMaxSlider.addEventListener('mousedown', function () {
thumbRight.classList.add('active');
});
PriceMaxSlider.addEventListener('mouseup', function () {
thumbRight.classList.remove('active');
});
//Range Price Slider Script End
// Range Delivery Slider Script
var MinDeliverySlider = document.getElementById('min-delivery-slider');
var MaxDeliverySlider = document.getElementById('max-delivery-slider');
var thumbLeft2 = document.querySelector('.multi-range-slider2 > .slider > .thumb.left');
var thumbRight2 = document.querySelector('.multi-range-slider2 > .slider > .thumb.right');
var range2 = document.querySelector('.multi-range-slider2 > .slider > .range');
var tooltipLeft2 = document.getElementById('tooltip-left2');
var tooltipRight2 = document.getElementById('tooltip-right2');
function setLeftValue2() {
var _this = MinDeliverySlider,
min = parseInt(_this.min),
max = parseInt(_this.max);
_this.value = Math.min(
parseInt(_this.value),
parseInt(MaxDeliverySlider.value) - 1
);
var percent = ((_this.value - min) / (max - min)) * 100;
thumbLeft2.style.left = percent + '%';
range2.style.left = percent + '%';
updateTooltipPosition2();
}
setLeftValue2();
function setRightValue2() {
var _this = MaxDeliverySlider,
min = parseInt(_this.min),
max = parseInt(_this.max);
_this.value = Math.max(
parseInt(_this.value),
parseInt(MinDeliverySlider.value) + 1
);
var percent = ((_this.value - min) / (max - min)) * 100;
thumbRight2.style.right = 100 - percent + '%';
range2.style.right = 100 - percent + '%';
updateTooltipPosition2();
}
setRightValue2();
function updateTooltipPosition2() {
var thumbLeftPosition2 = thumbLeft2.getBoundingClientRect();
var thumbRightPosition2 = thumbRight2.getBoundingClientRect();
tooltipLeft2.style.display = 'block';
tooltipLeft2.style.left = thumbLeftPosition2.left + 'px';
tooltipLeft2.style.top = thumbLeftPosition2.bottom + 5 + 'px';
tooltipLeft2.innerHTML = MinDeliverySlider.value;
tooltipRight2.style.display = 'block';
tooltipRight2.style.left = thumbRightPosition2.left + 'px';
tooltipRight2.style.top = thumbRightPosition2.bottom + 5 + 'px';
tooltipRight2.innerHTML = MaxDeliverySlider.value;
}
MinDeliverySlider.addEventListener('input', setLeftValue2);
MaxDeliverySlider.addEventListener('input', setRightValue2);
MinDeliverySlider.addEventListener('mousedown', function () {
thumbLeft2.classList.add('active');
});
MinDeliverySlider.addEventListener('mouseup', function () {
thumbLeft2.classList.remove('active');
});
MaxDeliverySlider.addEventListener('mousedown', function () {
thumbRight2.classList.add('active');
});
MaxDeliverySlider.addEventListener('mouseup', function () {
thumbRight2.classList.remove('active');
});
// Range Bid Slider Script
var MinBidSlider = document.getElementById('min-bid-slider');
var MaxBidSlider = document.getElementById('max-bid-slider');
var thumbLeft3 = document.querySelector('.multi-range-slider3 > .slider > .thumb.left');
var thumbRight3 = document.querySelector('.multi-range-slider3 > .slider > .thumb.right');
var range3 = document.querySelector('.multi-range-slider3 > .slider > .range');
var tooltipLeft3 = document.getElementById('tooltip-left3');
var tooltipRight3 = document.getElementById('tooltip-right3');
function setLeftValue3() {
var _this = MinBidSlider,
min = parseInt(_this.min),
max = parseInt(_this.max);
_this.value = Math.min(
parseInt(_this.value),
parseInt(MaxBidSlider.value) - 1
);
var percent = ((_this.value - min) / (max - min)) * 100;
thumbLeft3.style.left = percent + '%';
range3.style.left = percent + '%';
updateTooltipPosition3();
}
setLeftValue3();
function setRightValue3() {
var _this = MaxBidSlider,
min = parseInt(_this.min),
max = parseInt(_this.max);
_this.value = Math.max(
parseInt(_this.value),
parseInt(MinBidSlider.value) + 1
);
var percent = ((_this.value - min) / (max - min)) * 100;
thumbRight3.style.right = 100 - percent + '%';
range3.style.right = 100 - percent + '%';
updateTooltipPosition3();
}
setRightValue3();
function updateTooltipPosition3() {
var thumbLeftPosition3 = thumbLeft3.getBoundingClientRect();
var thumbRightPosition3 = thumbRight3.getBoundingClientRect();
tooltipLeft3.style.display = 'block';
tooltipLeft3.style.left = thumbLeftPosition3.left + 'px';
tooltipLeft3.style.top = thumbLeftPosition3.bottom + 5 + 'px';
tooltipLeft3.innerHTML = MinBidSlider.value;
tooltipRight3.style.display = 'block';
tooltipRight3.style.left = thumbRightPosition3.left + 'px';
tooltipRight3.style.top = thumbRightPosition3.bottom + 5 + 'px';
tooltipRight3.innerHTML = MaxBidSlider.value;
}
MinBidSlider.addEventListener('input', setLeftValue3);
MaxBidSlider.addEventListener('input', setRightValue3);
MinBidSlider.addEventListener('mousedown', function () {
thumbLeft3.classList.add('active');
});
MinBidSlider.addEventListener('mouseup', function () {
thumbLeft3.classList.remove('active');
});
MaxBidSlider.addEventListener('mousedown', function () {
thumbRight3.classList.add('active');
});
MaxBidSlider.addEventListener('mouseup', function () {
thumbRight3.classList.remove('active');
});
</script>
</body>
</html>

The values of
.getBoundingClientRect()are relative to the top left corner of the viewport. When you apply the results of this call as-is onto the tooltips via the.leftproperty, it would be relative to their nearest position parent . Thus we should "undo" this offset. We can get their respective position parents by reading.offsetParentproperty and then getting its top-left corner viewport relative values from its own.getBoundingClientRect(). Subtracting theleftfrom the original.getBoundingClientRect()will give us a relative value that would exhibit the behavior I believe you are after: