Animated Numeric Stepper Component In jQuery

Animated Numeric Stepper Component In jQuery
File Size: 612 KB
Views Total:
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   

An awesome animated numeric stepper (aka. input spinner) component which can be used to increment or decrement a value by clicking arrows.

Requires jQuery and anime.js libraries.

How to use it:

1. Create the HTML for the stepper. You can specify the starting number in the data-start attribute and set the direction using the horizontal or vertical class.

<!-- Vertical -->
<div class="stepper vertical" data-start="123">
  <img src="img/arrow.svg" class="arrow top" alt=""/>
  <div class="box">
    <div class="numbers1 active">
      <span>1</span>
      <span>2</span>
      <span>3</span>
    </div>
    <div class="numbers2">
      <span></span>
      <span></span>
      <span></span>
    </div>
  </div>
  <img src="img/arrow.svg" class="arrow bottom" alt=""/>
</div>

<!-- Horizontal -->
<div class="stepper horizontal" data-start="123">
  <img src="img/arrow.svg" class="arrow top" alt=""/>
  <div class="box">
    <div class="numbers1 active">
      <span>1</span>
      <span>2</span>
      <span>3</span>
    </div>
    <div class="numbers2">
      <span></span>
      <span></span>
      <span></span>
    </div>
  </div>
  <img src="img/arrow.svg" class="arrow bottom" alt=""/>
</div>

2. The necessary CSS/CSS3 styles.

.stepper.horizontal,.stepper.vertical{
  position:relative;
  text-align:center;
  width:300px;
  height:300px
}

.stepper.vertical .arrow{
  width:70px;
  opacity:.5;
  -webkit-transition:all .2s ease-in-out;
  -o-transition:all .2s ease-in-out;
  transition:all .2s ease-in-out;
  cursor:pointer;
  position:relative
}

.stepper.vertical .arrow:hover{
  opacity:1
}

.stepper.vertical .arrow.top{
  -webkit-transform:rotate(90deg);
  -ms-transform:rotate(90deg);
  transform:rotate(90deg);
  top:25px
}

.stepper.vertical .arrow.bottom{
  -webkit-transform:rotate(-90deg);
  -ms-transform:rotate(-90deg);
  transform:rotate(-90deg);
  margin-top:16px;
  top:-20px
}

.stepper.vertical .box{
  overflow:hidden;
  height:92px;
  position:relative;
  padding:10px 0
}

.stepper.vertical .box::after,.stepper.vertical .box::before{
  content:'';
  position:absolute;
  left:0;
  right:0;
  height:20px;
  background:-webkit-gradient(linear,left top,left bottom,from(#ff6f72),to(rgba(125,185,232,0)));
  background:-webkit-linear-gradient(top,#ff6f72 0%,rgba(125,185,232,0) 100%);
  background:-o-linear-gradient(top,#ff6f72 0%,rgba(125,185,232,0) 100%);
  background:linear-gradient(to bottom,#ff6f72 0%,rgba(125,185,232,0) 100%);
  filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ff6f72', endColorstr='#007db9e8',GradientType=0 );
  z-index:1
}

.stepper.vertical .box::before{
  top:0
}

.stepper.vertical .box::after{
  bottom:0;
  -webkit-transform:rotate(180deg);
  -ms-transform:rotate(180deg);
  transform:rotate(180deg)
}

.stepper.horizontal .box span,.stepper.vertical .box span{
  display:inline-block;
  letter-spacing:1px;
  -webkit-user-select:none;
  -moz-user-select:none;
  -ms-user-select:none;
  user-select:none
}

.stepper.vertical .box .numbers1,.stepper.vertical .box .numbers2{
  position:absolute;
  top:12px;
  left:80px;
  display:-webkit-box;
  display:-webkit-flex;
  display:-ms-flexbox;
  display:flex
}

.stepper.vertical .box .numbers1 span{
  -webkit-transform:translateY(0);
  -ms-transform:translateY(0);
  transform:translateY(0)
}

.stepper.vertical .box .numbers2 span{
  -webkit-transform:translateY(90px);
  -ms-transform:translateY(90px);
  trans
  form:translateY(90px)
}
.stepper.horizontal{
  height:119px
}

.stepper.horizontal .arrow{
  width:70px;
  opacity:.5;
  -webkit-transition:all .2s ease-in-out;
  -o-transition:all .2s ease-in-out;
  transition:all .2s ease-in-out;
  cursor:pointer;
  position:absolute
}

.stepper.horizontal .arrow:hover{
  opacity:1
}

.stepper.horizontal .arrow.top{
  -webkit-transform:translateY(-50%);
  -ms-transform:translateY(-50%);
  transform:translateY(-50%);
  top:59px;
  left:-11px
}

.stepper.horizontal .arrow.bottom{
  -webkit-transform:rotate(180deg) translateY(-50%);
  -ms-transform:rotate(180deg) translateY(-50%);
  transform:rotate(180deg) translateY(-50%);
  top:-12px;
  right:-11px
}

.stepper.horizontal .box{
  overflow:hidden;
  height:92px;
  position:relative;
  padding:10px 0;
  margin:0 50px
}

.stepper.horizontal .box::after,.stepper.horizontal .box::before{
  content:'';
  position:absolute;
  top:0;
  bottom:0;
  width:20px;
  background:-webkit-gradient(linear,left top,right top,from(#ff6f72),to(rgba(125,185,232,0)));
  background:-webkit-linear-gradient(left,#ff6f72 0%,rgba(125,185,232,0) 100%);
  background:-o-linear-gradient(left,#ff6f72 0%,rgba(125,185,232,0) 100%);
  background:linear-gradient(to right,#ff6f72 0%,rgba(125,185,232,0) 100%);
  filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ff6f72', endColorstr='#007db9e8',GradientType=1 );
  z-index:1
}

.stepper.horizontal .box::before{
  left:0
}

.stepper.horizontal .box::after{
  right:0;
  -webkit-transform:rotate(180deg);
  -ms-transform:rotate(180deg);
  transform:rotate(180deg)
}

.stepper.horizontal .box .numbers1,.stepper.horizontal .box .numbers2{
  position:absolute;
  top:12px;
  left:31px;
  display:-webkit-box;
  display:-webkit-flex;
  display:-ms-flexbox;
  display:flex
}

.stepper.horizontal .box .numbers1 span{
  -webkit-transform:translateX(0);
  -ms-transform:translateX(0);
  transform:translateX(0)
}

.stepper.horizontal .box .numbers2 span{
  -webkit-transform:translateX(185px);
  -ms-transform:translateX(185px);
  transform:translateX(185px)
}

3. Include the necessary jQuery and anime.js libraries at the bottom of the page.

<script src="/path/to/jquery.min.js"></script>
<script src="/path/to/anime.min.js"></script>

4. The main JavaScript to enable the stepper.

let number = document.querySelector('.stepper.vertical').getAttribute('data-start');
let numberH = document.querySelector('.stepper.horizontal').getAttribute('data-start');
let tl = anime.timeline();
let trigger = true;

let eachNumberDelay = 50;
let speed = 1800;

// FOR VERTICAL

$('body').on('click', '.vertical .arrow.top', () => {
  if (trigger) {
    trigger = false;
    number++;

    setTimeout(() => {
      trigger = true;
    }, 400);

    setNumbers(number, '.vertical');

    tl.pause();  
    
    tl = anime.timeline();
  
    tl.add({
      targets: '.vertical .box > div:not(.active) span',
      translateY: -95,
      duration: 0
    })
    .add({
      targets: '.vertical .box > div.active span',
      translateY: 95,
      delay: anime.stagger(eachNumberDelay),
      duration: speed
    })
    .add({
      targets: '.vertical .box > div:not(.active) span',
      translateY: 0,
      delay: anime.stagger(eachNumberDelay),
      duration: speed
    }, '-=' + speed * 1.06);
  
    changeClass('.vertical');
  }  
});


$('body').on('click', '.vertical .arrow.bottom', () => {
  if (trigger) {
    trigger = false;
    number--;

    setTimeout(() => {
      trigger = true;
    }, 400);

    setNumbers(number, '.vertical');
  
    tl.pause();  
    
    tl = anime.timeline();
  
    tl.add({
      targets: '.vertical .box > div:not(.active) span',
      translateY: 95,
      duration: 0
    })
    .add({
      targets: '.vertical .box > div.active span',
      translateY: -95,
      delay: anime.stagger(eachNumberDelay),
      duration: speed
    })
    .add({
      targets: '.vertical .box > div:not(.active) span',
      translateY: 0,
      delay: anime.stagger(eachNumberDelay),
      duration: speed
    }, '-=' + speed * 1.06);
  
    changeClass('.vertical');
  }
});

// FOR HORIZONTAL

$('body').on('click', '.horizontal .arrow.top', () => {
  if (trigger) {
    trigger = false;
    numberH--;

    setTimeout(() => {
      trigger = true;
    }, 400);

    setNumbers(numberH, '.horizontal');
  
    tl.pause();  
    
    tl = anime.timeline();

    anime({
      targets: '.horizontal .box > div:not(.active) span',
      translateX: -185,
      duration: 0
    })
  
    tl.add({
      targets: '.horizontal .box > div.active span',
      translateX: 185,
      easing: 'spring(1, 80, 10, 0)',
      delay: anime.stagger(30),
    })
    .add({
      targets: '.horizontal .box > div:not(.active) span',
      translateX: 0,
      easing: 'spring(1, 80, 10, 0)',
      delay: anime.stagger(30),
    }, '-=' + speed / 1.1);
  
    changeClass('.horizontal');
  }
});

$('body').on('click', '.horizontal .arrow.bottom', () => {
  if (trigger) {
    trigger = false;
    numberH++;

    setTimeout(() => {
      trigger = true;
    }, 400);

    setNumbers(numberH, '.horizontal');

    tl.pause();  
    
    tl = anime.timeline();

    anime({
      targets: '.horizontal .box > div:not(.active) span',
      translateX: 185,
      duration: 0
    })    
  
    tl.add({
      targets: '.horizontal .box > div.active span',
      translateX: -185,
      duration: speed,
      easing: 'spring(1, 80, 10, 0)',
      delay: anime.stagger(30),
    })
    .add({
      targets: '.horizontal .box > div:not(.active) span',
      translateX: 0,
      duration: speed,
      easing: 'spring(1, 80, 10, 0)',
      delay: anime.stagger(30),
    }, '-=' + speed / 1.1);
  
    changeClass('.horizontal');
  }  
});



let setNumbers = (number, direction) => {
  $('.stepper' + direction + ' .box > div:not(.active)').html('');
  
  for (char of number.toString()) {
    $('.stepper' + direction + ' .box > div:not(.active)').append('<span>' + char + '</span>');
  }
}

let changeClass = (direction) => {
  if ($('.stepper' + direction + ' .numbers1').hasClass('active')) {
    $('.stepper' + direction + ' .numbers1').removeClass('active');
    $('.stepper' + direction + ' .numbers2').addClass('active');
  } else {
    $('.stepper' + direction + ' .numbers2').removeClass('active');
    $('.stepper' + direction + ' .numbers1').addClass('active');
  }
}

Changelog:

2019-04-23

  • Bugfix

This awesome jQuery plugin is developed by alikinvv. For more Advanced Usages, please check the demo page or visit the official website.