By using a "illusion" element to pretend to be part of the slider you can achieve an effect like you wish to do.
I'm not all to familiar with ReactJS as of yet, so I coded it in vanilla javascript, but it should be easy enough to convert to react code.
By listening to the change and input events on the slider, you can update the "illusion" to become smaller or larger.
By listening to clicks on the illusion, you can make the slider have a larger value and then trigger the change event to update the width of the illusion.
Do note that I used scoped references in my code. Depending on your code base you might wish to make these class properties or fetch them anew every time an event is triggered.
Hopefully this gives you inspiration enough to come up to a react solution.
/**
* getting all the sliders in the document.
* define how big the thumb is here.
*/
const SLIDER_THUMB_SIZE = 8;
Array.from(document.querySelectorAll('.slider'))
.forEach(function(element) {
/** a reference to our illusion of a slider **/
let illusion = element.parentNode.querySelector('.slider-illusion');
/** We need this to save our state without having to look it up on the element **/
let currentWidth;
/** Our change handler, to update the width of our thin slider piece **/
let changeWidth = (e) => {
/** get the current actual width of our input element **/
let width = parseInt(window.getComputedStyle(element).getPropertyValue("width"));
/** Calculate the left offset **/
let left = ((element.value - element.min) / (element.max - element.min)) * ((width - SLIDER_THUMB_SIZE)) + SLIDER_THUMB_SIZE * 1.25 ;
/** set the proper width **/
illusion.style.width = (width - left + SLIDER_THUMB_SIZE) + "px";
/** update out position **/
illusion.style.left = left+"px" ;
};
/** When a click is registered on the illusion, we need to update our
value in the slider. **/
let illusionTrigger = (e) => {
/** Where was clicked in the illusion? **/
let offset = e.offsetX;
/** how wide are the parts in our illusion for each change **/
let part = illusion.clientWidth / (element.max - element.value) ;
/** calculate the value that needs to be added to the current slider value **/
let change = Math.round(offset / part);
/** force a change if there is a click behind the thumb **/
if(change == 0) {
change = 1;
}
/** update the slider **/
element.value = parseInt(element.value) + change;
/** Trigger a change notification and a redraw of the illusion **/
element.dispatchEvent(new Event('change'));
};
/** trigger it once to update everything to the correct position **/
changeWidth();
/** bind the event handler to the input and change event to enable dragging of the thumb**/
element.addEventListener('input', changeWidth);
element.addEventListener('change', changeWidth);
let forFun = (e) => {
document.getElementById(element.name).innerText = element.value;
};
element.addEventListener('input', forFun);
element.addEventListener('change', forFun);
/** listen to the click event on the illusion **/
illusion.addEventListener('click', illusionTrigger);
});
.slider-container {
position:relative;
height: 10px;
width: 100%;
overflow: hidden;
}
.slider-illusion {
position: absolute;
top:0px;
background: white;;
width: 50%;
left: calc(50% + 2px);
height:10px;
cursor: pointer;
}
.slider-illusion .line {
position: absolute;
top: 3px;
height: 2px;
background-color: black;
width: 100%;
}
.slider {
/**
* absolute positioning to assure both elements align the same
*/
position:absolute;
top:0px;
left:0px;
width: 100%;
height: 5px;
outline: none;
background: #393837;
-webkit-appearance: none;
}
.slider::-webkit-slider-thumb {
width: 8px;
height: 8px;
cursor: pointer;
appearance: none;
background: black;
border-radius: 50%;
-webkit-appearance: none;
}
.slider::-moz-range-thumb {
width: 8px;
height: 8px;
border: none;
cursor: pointer;
border-radius: 50%;
background: black;
}
Select how many cups you want: <span id="cups">3</span>/5
<div class="slider-container">
<input min="1" max="5" value="3" type="range" class="slider" name="cups" />
<div class="slider-illusion" data-width="50%">
<div class="line"></div>
</div>
</div>
<br>
Select how many balls you want: <span id="balls">125</span>/500
<div class="slider-container">
<input min="1" max="500" value="125" type="range" class="slider" name="balls" />
<div class="slider-illusion" data-width="50%">
<div class="line"></div>
</div>
</div>
<br>
select how many rounds to play: <span id="rounds">3</span>/10
<div class="slider-container">
<input min="1" max="10" value="3" type="range" class="slider" name="rounds"/>
<div class="slider-illusion" data-width="50%">
<div class="line"></div>
</div>
</div>