skip to Main Content

I contain a slider which uses an input range the current numbers are

12, 24, 36, 48, 60

I need to add the ability to contain

24, 36, 48, 60, 120

<input type="range" data-id='slider1RangePicker' name="range"
       class="form-range slider range" min="24" max="120" step="12"
       id="slider1">

<ul class="range-labels">
 <li class="active selected">24</li>
 <li>36</li>
 <li>48</li>
 <li>60</li>
 <li>120</li>
</ul>

previously I would set the min as 12 max as 60 and then a step of 12 which allows it to range correctly.

However with adding 120 and removing 24 and setting the min max accordingly the step number no longer works because of the 60-120 jump.

How would I solve this?

2

Answers


  1. You should have a contiguous range from 0..max. You no longer have a linear axis, it it essentially a category axis now.

    You can use JavaScript to synchronize the labels to the slider like so:

    Note: To get the current value, you can use getSlider($rangeSlider).dataset.value.

    const $rangeSlider = document.querySelector('.range-slider');
    
    // Handle slider change
    $rangeSlider.addEventListener('change', (e) => {
      syncRangeSlider(e.currentTarget);
    });
    
    // Handle label click
    $rangeSlider.addEventListener('click', (e) => {
      if (e.target.tagName === 'LI') {
        getSlider(e.currentTarget).value = getElementIndex(e.target);
      }
      syncRangeSlider(e.currentTarget);
    });
    
    // Initial sync
    syncRangeSlider($rangeSlider);
    
    function syncRangeSlider(rangeSliderEl) {
      const slider = getSlider(rangeSliderEl);
      const index = slider.valueAsNumber;
      let labelValue;
      getLabels(rangeSliderEl).forEach((label, currIndex) => {
        const isActive = currIndex === index;
        if (isActive) {
          labelValue = +label.textContent;
        }
        toggleLabelActive(label, isActive);
      });
      slider.dataset.value = labelValue;
    }
    
    function toggleLabelActive(label, active) {
      label.classList.toggle('active', active);
      label.classList.toggle('selected', active);
    }
    
    function getSlider(rangeSliderEl) {
      return rangeSliderEl.querySelector('.slider.range');
    }
    
    function getLabels(rangeSliderEl) {
      return rangeSliderEl.querySelectorAll('.range-labels li');
    }
    
    function getElementIndex(element) {
      return Array.prototype.indexOf.call(element.parentNode.children, element);
    }
    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
    }
    
    body {
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .range-slider {
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
      padding: 0.5rem;
      border: thin solid #AAA;
      border-radius: 0.5rem;
      background: #EEE;
    }
    
    .range-slider .slider.range {
      margin: 0 0.5rem;
    }
    
    .range-slider .range-labels {
      display: flex;
      gap: 0.25rem;
      margin: 0;
      padding: 0;
      list-style-type: none;
    }
    
    .range-slider .range-labels li {
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0;
      padding: 0;
      border: thin solid #CCC;
      background: #F7F7F7;
      border-radius: 50%;
      min-width: 2rem;
      aspect-ratio: 1 / 1;
      cursor: pointer;
      user-select: none;
    }
    
    .range-slider .range-labels li.active.selected {
      background: #FFA;
    }
    <div class="range-slider">
      <input
        type="range"
        id="slider1"
        name="range"
        class="form-range slider range"
        data-id="slider1RangePicker"
        min="0"
        max="4"
        value="1"
        data-value="24" />
      <ul class="range-labels">
       <li class="active selected">24</li>
       <li>36</li>
       <li>48</li>
       <li>60</li>
       <li>120</li>
      </ul>
    </div>
    Login or Signup to reply.
  2. The list attribute and datalist element can be used to specify the values.

    You will also need a small script to block the intermediate positions.

    const sliderInput = document.querySelector('#slider1');
    const sliderValOpts = document.querySelectorAll('#slider1Values option');
    
    const valOut = document.querySelector("#valueOutput");
    valOut.textContent = sliderInput.value;
    
    sliderInput.addEventListener('input', (evt) => {
      const evtVal = parseInt(evt.target.value);
      for (const opt of sliderValOpts) {
        const val = parseInt(opt.value);
        if (val >= evtVal) {
          evt.target.value = val;
          break;
        }
      }
      valOut.textContent = event.target.value;
    });
    <input type="range" data-id="slider1RangePicker" name="range" class="form-range slider range" min="24" max="120" step="1" id="slider1" list="slider1Values" value="60">
    
    <datalist id="slider1Values">
      <option value="24"></option>
      <option value="36"></option>
      <option value="48"></option>
      <option value="60"></option>
      <option value="120"></option>
    </datalist>
    
    <p>Value: <output id="valueOutput"></output></p>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search