Martin
Martin

Reputation: 22760

How to always display numerical input spinners on mobile and iPad

I have some HTML/CSS that works perfectly on desktop.

It also works on mobile, but the up and down arrows for numerical selection on the input field do not display, forcing the user to "enter" the number manually. The client has requested these numerical spinner arrows are retained on mobile view.

There are a lot of questions about how to hide/disable spinners and even a few about how to retain the spinners, but these have no or incorrect answers and following these answers and suggestions has not resolved this issue.

        @media only screen {

            input[type=number] {
               /* -moz-appearance: number-input; */   
            }
 
            input[type=number]::-webkit-inner-spin-button,
            input[type=number]::-webkit-outer-spin-button {
                -webkit-appearance: inner-spin-button;
                /***
                 * Below tried and failed: 
                 ***/
                /* -moz-appearance: number-input; */ 
                /*-ms-appearance: inner-spin-button;*/
                /*appearance: auto;*/
                margin: 0;
                opacity: 1;
            }
            
            #updQtyLoose47 {
             /* basic styling */
            background: rgba(245, 235, 170, 0.75);
            border-radius: 0;
            border: none;
            border: solid 1px #dbdbdb;
            color: inherit;
            display: block;
            outline: 0;
            padding: 0.25rem 0 0.25rem 0.75rem;
            text-decoration: none;
            width: 100px;
            }
        }
<div>
<input type="number" name="Quantity[47]" value="0" class="qtyInputLoose" id="updQtyLoose47" min="0" max="8" >
</div>

Platform:

iPad (iOS 12.5)

Browsers:

Google Chrome and Safari

Attempted solutions:

iPad simulators (for what they're worth) on PC on Firefox Inspector shows the spinner buttons, and Google Chrome Inspector they do NOT show the spinner buttons.

There is a comment here that

In firefox and safari, its a default feature to show it always.

This no longer appears to be the case for Safari 12.1

How can I show these input spinner buttons on iPad display of the webpage?

Upvotes: 5

Views: 10841

Answers (3)

Pietro
Pietro

Reputation: 177

I have been looking for so long to show arrows on Mobile Chrome when I realized that the operating system deals differently with inputs (popping up the keyboard and not showing arrows). I came across this post and I have improved the code to make that you can have many buttons in the same page but just one function to manage the increment/decrement of each. The final example is like in the picture below for smartphones.

To add a third button just make the input with id='3' and the button with plus sign with id='pb3' and the button with minus side with id='mb3' You do not need to change anything else

You can either use the onchange event or the onkeyup event to call imposeMinMax() function. Depending on your application. onkeyup works well only if you have a min<0 and max>0.

I have also added autoincrement input when the user keeps the button pressed. Visit this link for the autoincrement code.

enter image description here

function imposeMinMax(el){ /*this function delimits max and min*/
  if(el.value != ""){
    if(parseInt(el.value) < parseInt(el.min)){
      el.value = el.min;
    }
    if(parseInt(el.value) > parseInt(el.max)){
      el.value = el.max;
    }
  }
}

function modIn(inId){
  if(inId.charAt(0)=='p'){                  /*p for plus*/
    var targetId = inId.match(/\d+/)[0];    /*just keep the number*/
    document.getElementById(targetId).value ++;
    imposeMinMax(document.getElementById(targetId));
  } 
  if(inId.charAt(0)=='m'){                  /*m for minus*/
    var targetId = inId.match(/\d+/)[0];
    document.getElementById(targetId).value --;
    imposeMinMax(document.getElementById(targetId));
  } 
}
.signBut {
      width: 30px;
      margin-bottom: 5px;
    }

.inNum {width: 40px;}
  
<!--    Bootstrap --> 
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<div class='card'>
  <div class='card-body' >
    <h5 class='card-title'>TEMPERATURE</h5>
      <div class='container'>
        <div class='row'>
          <div class='col-auto' style="width: 40%;">
            <label >Temprerature:</label>
          </div>
          <div class='col-auto'>
            <button type="button" class="btn btn-danger btn-sm signBut" id='mb1' onclick='modIn(this.id)'>-</button>
            <input type="number" name='tempCalib' id='1' class='inNum' onchange='imposeMinMax(this)' value='0' max='6' min="-6" step="1">                 
            <button type="button" class="btn btn-danger btn-sm signBut" id='pb1' onclick='modIn(this.id)'>+   </button>&nbsp;°C
          </div>
        </div>
        <br>
        <div class='row'>
          <div class='col-auto' style="width: 40%;">
            <label>Hysteresis:</label>
          </div>
          <div class='col-auto'>
            <button type="button" class="btn btn-danger btn-sm signBut" id='mb2' onclick='modIn(this.id)'>-</button>
            <input type="number" name='tempHyst' id='2' class='inNum' onchange='imposeMinMax(this)' value="1" max="4" min="-4" step="1">                 
            <button type="button" class="btn btn-danger btn-sm signBut" id='pb2' onclick='modIn(this.id)'>+</button>&nbsp;°C
          </div>
         </div>
        </div>
       </div>
      </div>

Upvotes: 2

johannchopin
johannchopin

Reputation: 14844

At some point it's hard and tricky to get a consistent result across the platforms for a native element like an input. For this reason, I would recommend you to re-create one that 'fake' the native behaviour by using some javascript. Here is a very basic example:

const input = document.querySelector('input[type=number]')

const increment = () => {
  input.value = Number(input.value) + 1
}
const decrement = () => {
  input.value = Number(input.value) - 1
}

document.querySelector('.spinner.increment').addEventListener('click', increment)
document.querySelector('.spinner.decrement').addEventListener('click', decrement)
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.number-input {
  position: relative;
  width: fit-content;
}

input {
  width: 60px;
}

.spinners {
  position: absolute;
  right: 0;
  top: 50%;
  display: flex;
  flex-direction: column;
  width: fit-content;
  margin: 1px;
  transform: translateY(-50%);
}

.spinner {
  font-size: 7px;
  border: none;
  padding: 0 1px;
}

.spinner:hover {
  background: lightgrey;
}
<div class="number-input">
  <input type="number" name="Quantity[47]" value="0" class="qtyInputLoose" min="0" max="8">
  <div class="spinners">
    <button class="spinner increment">&#9650;</button>
    <button class="spinner decrement">&#9660;</button>
  </div>
</div>

If you need something more customised, simply adjust a little bit of css and html structure:

const input = document.querySelector('input[type=number]')

const increment = () => {
  input.value = Number(input.value) + 1
}
const decrement = () => {
  input.value = Number(input.value) - 1
}

document.querySelector('.spinner.increment').addEventListener('click', increment)
document.querySelector('.spinner.decrement').addEventListener('click', decrement)
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.number-input {
  display: flex;
}

input {
  width: 40px;
  border: solid 1px lightgrey;
  border-radius: 0;
  text-align: center
}

.spinner {
  border: solid 1px lightgrey;
}

.spinner:hover {
  background: lightgrey;
}

.spinner:first-child {
  border-radius: 3px 0 0 3px;
}

.spinner:last-child {
  border-radius: 0 3px 3px 0;
}
<div class="number-input">
  <button class="spinner decrement">-</button>
  <input type="number" name="Quantity[47]" value="0" class="qtyInputLoose" min="0" max="8">
  <button class="spinner increment">+</button>
</div>

Here is a version with JQuery:

const input = $('input[type=number]')

const increment = () => {
  input.val(Number(input.val()) + 1)
}
const decrement = () => {
  input.val(Number(input.val()) - 1)
}

$('.spinner.increment').click(increment)
$('.spinner.decrement').click(decrement)
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.number-input {
  display: flex;
}

input {
  width: 40px;
  border: solid 1px lightgrey;
  border-radius: 0;
  text-align: center
}

.spinner {
  border: solid 1px lightgrey;
}

.spinner:hover {
  background: lightgrey;
}

.spinner:first-child {
  border-radius: 3px 0 0 3px;
}

.spinner:last-child {
  border-radius: 0 3px 3px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<div class="number-input">
  <button class="spinner decrement">-</button>
  <input type="number" name="Quantity[47]" value="0" class="qtyInputLoose" min="0" max="8">
  <button class="spinner increment">+</button>
</div>

Upvotes: 7

Subbu Sharma
Subbu Sharma

Reputation: 144

You can try to check this example here for this

Upvotes: -1

Related Questions