Search code examples
htmlcssreactjstailwind-css

How to create a range slider with different colored segments that fill in when slider is increased?


Trying to create a range slider like the one here. Can't seem to figure out to separate it into 3 different segments. Any help would be appreciated!

I was able to mess around with changing single colors. But still can't figure out how to do 3 different color segments.

CSS using Tailwind below

input[type='range'] {
        @apply w-full h-8 outline-none appearance-none rounded-3xl;
        background: linear-gradient(90deg, #7549ea 50%, #e7e4f2 50%);
    }

    input[type='range']::-webkit-slider-thumb {
        @apply w-8 h-8 -mt-[.65rem] rounded-full appearance-none cursor-pointer bg-secondary-dark;
    }

    input[type='range']::-webkit-slider-runnable-track {
        @apply h-2.5 appearance-none text-green mt-[-1px];
    }

    input[type='range']::-moz-range-thumb {
        @apply w-8 h-8 rounded-full appearance-none cursor-pointer bg-secondary-dark;
    }

    input[type='range']::-moz-range-progress {
        @apply bg-primary;
    }

    input[type='range']::-ms-thumb {
        @apply mt-0;
    }

    input[type='range']::-ms-fill-lower {
        @apply bg-primary;
    }

    input[type='range'].slider-sm {
        @apply w-full h-[1.5625rem] outline-none appearance-none rounded-3xl;
    }

    input[type='range'].slider-sm::-webkit-slider-thumb {
        @apply w-[1.5625rem] h-[1.5625rem] -mt-[.45rem] rounded-full appearance-none cursor-pointer bg-secondary-dark;
    }

    input[type='range']::-moz-range-thumb {
        @apply w-[1.5625rem] h-[1.5625rem] rounded-full appearance-none cursor-pointer bg-secondary-dark;
    }

Solution

  • const slider = document.getElementById('slider');
    const slider_mask = document.getElementsByClassName('slider-mask')[0];
    
    slider_mask.style.left = `${slider.value}%`;
    
    slider.addEventListener('input', (e) => {
      slider_mask.style.left = `${slider.value}%`;
    });
    .multistepSlider {
      width: 380px;
      height: 60px;
    }
    
    .step {
      display: flex;
      flex-direction: column;
      gap: 5px;
    }
    
    .Affordable {
      width: 200px;
    }
    
    .Stretch,
    .Aggressive {
      width: 80px;
    }
    
    .barContainer {
      display: flex;
      gap: 10px;
    }
    
    .bar {
      height: 25px;
      border-radius: 5px;
    }
    
    .multistepSlider>.barContainer>.step:nth-child(1)>.bar {
      background-color: #008254;
    }
    
    .multistepSlider>.barContainer>.step:nth-child(2)>.bar {
      background-color: #ffc764;
    }
    
    .multistepSlider>.barContainer>.step:nth-child(3)>.bar {
      background-color: #de2828;
    }
    
    .sliderContainer {
      position: absolute;
      width: 380px;
      top: 32px;
    }
    
    .slider-mask {
      position: absolute;
      width: 100%;
      height: 30px;
      background: rgba(255, 255, 255, 0.5);
    }
    
    input[type='range'] {
      position: absolute;
      width: 100%;
      -webkit-appearance: none;
      background-color: transparent;
    }
    
    input[type='range']::-webkit-slider-thumb {
      -webkit-appearance: none;
      appearance: none;
      border-radius: 20px;
      width: 30px;
      height: 30px;
      background: white;
      border: 1px solid gray;
      box-shadow: 0 0 5px gray;
      cursor: pointer;
    }
    <div class="multistepSlider">
      <div class="barContainer">
        <div class="Affordable step">
          <label>Affordable</label>
          <div class="bar"></div>
        </div>
        <div class="Stretch step">
          <label>Stretch</label>
          <div class="bar"></div>
        </div>
        <div class="Aggressive step">
          <label>Aggressive</label>
          <div class="bar"></div>
        </div>
      </div>
      <div class="sliderContainer">
        <div class="slider-mask"></div>
        <input type="range" id="slider" min="1" max="100" value="50" />
      </div>
    </div>

    I saw how to implement your request on site that you provide. and the way is split slider and 3 pieces slider bar background.
    Draw 3 pieces and put slider over the slider-bar, and then demand on user input move translucent object to express disabled value.

    I just using pure-CSS, so if you need convert to tailwind-CSS.