<body>
  <main>
    <div class="field">
      <label class="text-label">Text label</label>
      <div class="inputslider" data-value="40" data-unit="%" data-values="20,25,30,35,40,45,50">
        <input type="text" name="input" autocomplete="off" readonly>
        <div class="values"></div>
        <div class="area">
          <div class="track"></div>
          <div class="fill"></div>
          <div class="knob"></div>
        </div>
      </div>
    </div>
  </main>
</body>
html {
  width: 100%;
  height: 100%;
}

body {
  background-color: #E6E9ED;
  width: 100%;
  height: 100%;
}

main {
  width: 100%;
  height: 100%;
  display: grid;
  align-items: center;
}

.field {
  background-color: #fff;
  width: 100%;
  max-width: 340px;
  padding: 20px;
  margin-left: auto;
  margin-right: auto;
  box-shadow: 0px 10px 20px 0px rgba(0,0,0,0.19), 0px 6px 6px 0px rgba(0,0,0,0.23);
  
  label {
    margin-bottom: 16px;
    display: block;
    font-weight: bold;
    font-size: 16px;
  }
}

.inputslider {
  position: relative;

  input {
    display: none;
  }

  .values {
    position: relative;
    margin-left: 14px;
    margin-right: 14px;
    height: 30px;
    margin-bottom: 8px;
    z-index: 1;

    span {
      position: absolute;
      top: 0;
      background-color: #E6E9ED;
      color: #434A54;
      line-height: 20px;
      padding: 0 10px;
      border-radius: 10px;
      text-align: center;
      white-space: nowrap;
      display: block;
      font-size: 12px;
      transform: translateX(-50%);
      z-index: 1;
      transition: all .2s ease;

      &.selected {
        background-color: #434A54;
        color: #fff;
        z-index: 2;
      }
    }
  }

  .area {
    position: relative;
    height: 28px;

    .track {
      position: absolute;
      top: 50%;
      left: 0;
      background-color: #E6E9ED;
      width: 100%;
      height: 6px;
      border-radius: 3px;
      z-index: 1;
      transform: translateY(-50%);
    }

    .fill {
      position: absolute;
      top: 50%;
      left: 0;
      background: #AAB2BD;
      width: 0;
      height: 6px;
      border-radius: 3px;
      z-index: 2;
      transform: translateY(-50%);
    }

    .knob {
      position: absolute;
      top: 0;
      left: 0;
      background-color: #434A54;
      width: 28px;
      height: 28px;
      border-radius: 50%;
      box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.1), 0px 7px 12px rgba(0, 0, 0, 0.12);
      z-index: 3;
    }
  }
}
View Compiled
Element.prototype.addClass = function(className)
{
  if(!this.classList.contains(className)){
    this.classList.add(className);
  }
};

Element.prototype.removeClass = function(className)
{
  if(this.classList.contains(className)){
    this.classList.remove(className);
  }
};

Array.prototype.first = function()
{
  return this[0];
}

Array.prototype.last = function()
{
  return this[this.length - 1];
}

document.querySelectorAll('.inputslider').forEach(
  (inputslider) => {
    let values = inputslider.dataset.values.split(','),
      value = parseFloat(inputslider.dataset.value),
      unit = '',
      min = parseFloat(values.first()),
      max = parseFloat(values.last()),
      input = inputslider.querySelector('input'),
      area = inputslider.querySelector('.area'),
      knob = inputslider.querySelector('.knob'),
      fill = inputslider.querySelector('.fill');

    if(inputslider.dataset.unit){
      unit = inputslider.dataset.unit;
    }

    values.forEach(
      (value, i) => {
        values[i] = value = parseFloat(value);

        let span = document.createElement('span');
        span.innerText = value + unit;
        span.setAttribute('data-value', value);

        if(i == 0){
          span.addClass('selected');
          input.value = value;
        }

        span.style.left = gsap.utils.mapRange(min, max, 0, 100, value) + '%';

        inputslider.querySelector('.values').appendChild(span);
      }
    );

    Draggable.create(knob, {
        type: 'x',
        edgeResistance: 1,
        bounds: area,
        throwProps: false,
        onDrag: function()
        {
          handleInputslider(this, false);
        },
        onDragEnd: function()
        {
          handleInputslider(this, true);
        }
      }
    );
  }
);

function handleInputslider(instance, snap)
{
  let inputslider = instance.target.closest('.inputslider'),
    fill = inputslider.querySelector('.fill'),
    values = inputslider.dataset.values.split(','),
    min = parseFloat(values.first()),
    max = parseFloat(values.last()),
    xPercent = gsap.utils.mapRange(0, instance.maxX, 0, 100, instance.x),
    relativeValue = gsap.utils.mapRange(0, instance.maxX, min, max, instance.x),
    finalValue = gsap.utils.snap(values, relativeValue),
    snapX = gsap.utils.mapRange(min, max, 0, instance.maxX, finalValue),
    fillWidth = gsap.utils.mapRange(0, instance.maxX, 0, 100, snapX);

  if(snap){
    gsap.to(instance.target, {duration: .2, x: snapX});
    gsap.to(fill, {duration: .2, width: fillWidth + '%'});
  }else{
    values.forEach(
      (value, i) => {
        values[i] = parseFloat(value);
      }
    );

    fill.style.width = xPercent + '%';

    inputslider.querySelectorAll('.values span').forEach(
      (span) => {
        if(parseFloat(span.dataset.value) == finalValue){
          span.addClass('selected');
        }else{
          span.removeClass('selected');
        }
      }
    );

    inputslider.querySelector('input').value = finalValue;
  }
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/Draggable.min.js