...
The stepper may also be known as a spinner or spin button.
...
Usage & Behavior
General Guidelines
...
Label - Where relevant, the preceding label should indicate the units of the value.
...
Intervals - The interval between each up/down click may vary according to the content type and the task.
By default, the interval should be 1 unit per button press.
In some cases, other intervals are more appropriate, depending on the task. For example, speed may be in intervals of 10 units per click (e.g. 60 kph - 70 kph - 80 kph).
Manually entering a value in the number field which is in between the defined intervals may be valid or invalid.
A valid value will be set.
An invalid value may be rounded up to the nearest valid value or ignored. (See Validations and Errors below).
Minimum and maximum values - When the stepper reaches the minimum or maximum value, the up/down buttons will be disabled respectively.
...
Long press on up/down buttons - will enable faster continuous increment or decrement.
States
State | Image | Comment |
---|---|---|
Regular | ||
Hover | ||
Active | ||
Disabled | ||
Read-Only | ||
Error | ||
Warning |
Focused | ||
Focused, Hover | ||
Focused, Active | ||
Focused, Disabled |
Interaction
Clicking the up/down buttons will increase or decrease the value by the defined interval:
When the number field is empty:
clicking the up button will populate the field with a value one interval above the minimum.
clicking the down button will populate the field with the minimum value.
| |
|
While focused on the number field, the up/down keys on the keyboard will increase/decrease the value. The number field will remain focused and the text cursor will remain in place.
The user may enter a numeric value using the keyboard.
When the numeric stepper is selected, the user can use the mouse wheel to increase/decrease the value.
Long press on up/down buttons will enable faster continuous increment or decrement.
Pressing the Tab key or clicking outside of the control will move the focus away from the stepper and set the defined value (or the last valid value).
Validations and Errors
...
When the stepper reaches the minimum or maximum value, the up/down buttons will be disabled respectively.
Other validations will be provided for invalid syntax, invalid numbers, and missing values. See Field Validation for more info.
...
In the focus state, typing will enter a value
Keyboard | Description |
---|---|
Tab | Navigates to the next component. |
Shift + tab | Navigates to the previous component. |
Space | N/A |
Enter | N/A |
Esc | N/A |
Arrows |
|
Home | Sets slider to its minimum value. |
End | Sets slider to its maximum value. |
Mouse | Date picker menu |
---|---|
Right click on numeric field | Set Focus on component |
Design
Zeplin link | |
---|---|
Code
Html macro | ||
---|---|---|
| ||
<link rel="stylesheet" href="https://ux.verint.com/bootstrap-4.0.0/dist/fonts/css/verint_lux.css"> <link rel="stylesheet" href="https://ux.verint.com/bootstrap-4.0.0/dist/css/bootstrap.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://ux.verint.com/bootstrap-4.0.0/dist/js/bootstrap.bundle.js"></script> <script src="https://ux.verint.com/bootstrap-4.0.0/dist/other/accessibility.js"></script> <script src="https://ux.verint.com/bootstrap-4.0.0/dist/other/prism.min.js"></script> <link rel="stylesheet" href="https://ux.verint.com/bootstrap-4.0.0/dist/other/prism-coy.min.css"> <div class="card"> <div class="card-header">Numeric Stepper <button id="toggleMarkup" type="button" class="btn btn-sm btn-outline-primary btn btn-fixed-width float-right m-0" onclick="$('pre' ).toggle()">Toggle Markup</button></div> <div class="card-body"> <form> <div class="form-group row"> <label for="inputKey" class="col-lg-2 col-form-label col-form-label-sm">Regular</label> <div class="col-lg-4"> <div class="form-control-container"> <input type="number" class="form-control form-control-sm" placeholder="Enter a number" min="0" max="100" value="0"> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm increment" tabindex="-1"> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm decrement" tabindex="-1"> <i class="icon-down"></i> </button> </div> </div> </div> <div class="col-lg-6"> <pre class="language-html"><code><script type="prism-html-markup"><div class="form-control-container"> <input type="number" class="form-control form-control-sm" placeholder="Enter a number" min="0" max="100" value="0"> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm increment" tabindex="-1"> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm decrement" tabindex="-1"> <i class="icon-down"></i> </button> </div> </div></script></code></pre> </div> </div> <div class="form-group row"> <label for="inputKey" class="col-lg-2 col-form-label col-form-label-sm">Disabled</label> <div class="col-lg-4"> <div class="form-control-container"> <input type="number" class="form-control form-control-sm" placeholder="Enter a number" min="0" max="100" value="0" disabled> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm increment" tabindex="-1" disabled> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm decrement" tabindex="-1" disabled> <i class="icon-down"></i> </button> </div> </div> </div> <div class="col-lg-6"> <pre class="language-html"><code><script type="prism-html-markup"><div class="form-control-container"> <input type="number" class="form-control form-control-sm" placeholder="Enter a number" min="0" max="100" value="0" disabled> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm increment" tabindex="-1" disabled> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm decrement" tabindex="-1" disabled> <i class="icon-down"></i> </button> </div> </div></script></code></pre> </div> </div> <div class="form-group row"> <label for="inputKey" class="col-lg-2 col-form-label col-form-label-sm">Read-Only</label> <div class="col-lg-4"> <div class="form-control-container"> <input type="number" class="form-control form-control-sm" placeholder="Enter a number" min="0" max="100" value="0" readonly> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm increment" tabindex="-1" disabled> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm decrement" tabindex="-1" disabled> <i class="icon-down"></i> </button> </div> </div> </div> <div class="col-lg-6"> <pre class="language-html"><code><script type="prism-html-markup"><div class="form-control-container"> <input type="number" class="form-control form-control-sm" placeholder="Enter a number" min="0" max="100" value="0" readonly> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm increment" tabindex="-1" disabled> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm decrement" tabindex="-1" disabled> <i class="icon-down"></i> </button> </div> </div></script></code></pre> </div> </div> <div class="form-group row"> <label for="inputKey" class="col-lg-2 col-form-label col-form-label-sm">Warning</label> <div class="col-lg-4"> <div class="form-control-container"> <input type="number" class="form-control form-control-sm is-warning" placeholder="Enter a number" min="0" max="100" value="0"> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm is-warning increment" tabindex="-1"> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm is-warning decrement" tabindex="-1"> <i class="icon-down"></i> </button> </div> </div> </div> <div class="col-lg-6"> <pre class="language-html"><code><script type="prism-html-markup"><div class="form-control-container"> <input type="number" class="form-control form-control-sm is-warning" placeholder="Enter a number" min="0" max="100" value="0"> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm is-warning increment" tabindex="-1"> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm is-warning decrement" tabindex="-1"> <i class="icon-down"></i> </button> </div> </div></script></code></pre> </div> </div> <div class="form-group row"> <label for="inputKey" class="col-lg-2 col-form-label col-form-label-sm">Error</label> <div class="col-lg-4"> <div class="form-control-container"> <input type="number" class="form-control form-control-sm is-invalid" placeholder="Enter a number" min="0" max="100" value="101"> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm is-invalid increment" tabindex="-1"> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm is-invalid decrement" tabindex="-1"> <i class="icon-down"></i> </button> </div> </div> </div> <div class="col-lg-6"> <pre class="language-html"><code><script type="prism-html-markup"><div class="form-control-container"> <input type="number" class="form-control form-control-sm is-invalid" placeholder="Enter a number" min="0" max="100" value="101"> <div class="btn-group btn-group-sm spinner-group"> <button type="button" class="btn btn-outline-light btn-sm is-invalid increment" tabindex="-1"> <i class="icon-up"></i> </button> <button type="button" class="btn btn-outline-light btn-sm is-invalid decrement" tabindex="-1"> <i class="icon-down"></i> </button> </div> </div></script></code></pre> </div> </div> </form> </div> </div> <script> // Spinner jQuery.propHooks.disabled = { set: function (el, value) { if (el.disabled !== value) { el.disabled = value; value && $(el).trigger('disabledSet'); !value && $(el).trigger('enabledSet'); } } }; $('.form-control[type="number"]').on('keypress', function(e){ return e.metaKey || // cmd/ctrl e.which <= 0 || // arrow keys e.which == 8 || // delete key /[0-9]/.test(String.fromCharCode(e.which)); // numbers }); $('.form-control[type="number"]').on('input', function(e){ if(!($(this).is(':disabled') || $(this).is('[readonly]'))) { let disableMinButton = (Number(this.value)) <= Math.abs(this.getAttribute('min')); $(this).siblings('.spinner-group').find('.decrement').prop("disabled", disableMinButton); let disableMaxButton = (Number(this.value)) >= Math.abs(this.getAttribute('max')); $(this).siblings('.spinner-group').find('.increment').prop("disabled", disableMaxButton); } $(this).toggleClass('is-invalid', $(this).is(':invalid')); $(this).siblings('.spinner-group').find('button').toggleClass('is-invalid', $(this).is(':invalid')); }); $('.form-control[type="number"]').trigger("input"); // update bars at startup function incr(elem) { stepper = $(elem).closest('.form-control-container').find('.form-control[type="number"]'); stepper.get(0).stepUp(1); stepper.trigger("input"); } function decr(elem) { stepper = $(elem).closest('.form-control-container').find('.form-control[type="number"]'); stepper.get(0).stepDown(1); stepper.trigger("input"); } var increment = $(".spinner-group .increment"); increment.on( "click", function() { incr(this); }); var decrement = $(".spinner-group .decrement"); decrement.on( "click", function() { decr(this); }); var incrTimeoutId = 0; $(increment).on('mousedown', function() { incrTimeoutId = setTimeout(() => {incrTimeoutId = setInterval(() => {incr(this);}, 40);}, 250); }).on('mouseup mouseleave disabledSet', function() { clearTimeout(incrTimeoutId); }); var decrTimeoutId = 0; $(decrement).on('mousedown', function() { decrTimeoutId = setTimeout(() => {decrTimeoutId = setInterval(() => {decr(this);}, 40);}, 250); }).on('mouseup mouseleave disabledSet', function() { clearTimeout(decrTimeoutId); }); </script> |
...