A Bootstrap 5 plugin to create input spinner elements for number input, by shaack.com engineering. Zero dependencies other than Bootstrap 5.
This version is compatible with Bootstrap 5. For Bootstrap 4 use the bootstrap4-compatible branch. npm versions 3.x are Bootstrap 5 compatible, versions 2.x Bootstrap 4 compatible.
License: MIT
The Bootstrap InputSpinner
disabled or
class,
change and input events on value
change like the native element,
This script enables the InputSpinner for all inputs with type='number'.
No extra css needed, just Bootstrap 5.
<script type="module">
import {InputSpinner} from "./src/InputSpinner.js"
for (const el of document.querySelectorAll("input[type='number']")) {
new InputSpinner(el)
}
</script>
Find the source code, more documentation and the npm package at
The following contains examples of the InputSpinner's main features
<input type="number"/>
<input type="number" value="500" min="0" max="1000" step="10"/>
<input type="number" value="4.5" data-decimals="2" min="0" max="9" step="0.1"/>
change and input events and
read the value from JavaScript
Type in a number to see the difference between change and input events.
Value on input:
Value on change:
const changedInput = document.getElementById("changedInput")
changedInput.addEventListener("input", function (event) {
document.getElementById("valueOnInput").textContent = event.target.value
})
changedInput.addEventListener("change", function (event) {
document.getElementById("valueOnChange").textContent = event.target.value
})
inputNet.addEventListener("input", function (event) {
inputGross.setValue(event.target.value * 1.19)
})
inputGross.addEventListener("input", function (event) {
inputNet.setValue(event.target.value / 1.19)
})
placeholder and requireddisabled, dynamically changingAttributes are handled dynamically.
buttonsOnly mode and disabled autoInterval
In buttonsOnly mode no direct text input is allowed, the text-input
gets the attribute readonly. But the plus and minus buttons still allow to change the value.
autoInterval: undefined additionally disables the auto increase/decrease, when you hold the
button.
new InputSpinner(element, {buttonsOnly: true, autoInterval: undefined})
Off by default, matching what modern browsers do with the native <input type="number">.
Pass mouseWheel: true to enable it. The listener is attached only while the input has focus,
so an unfocused spinner never hijacks page scroll.
new InputSpinner(element, {mouseWheel: true})
class attribute
Try to change the class to "is-invalid" or "text-info".
<input id="inputChangeClass" class="is-valid" type="number" value="50"/>
<label for="classInput">CSS Class</label>
<input id="classInput" type="text" class="form-control" value="is-valid"/>
<script>
document.getElementById("classInput").addEventListener("input", function (event) {
document.getElementById("inputChangeClass").className = event.target.value
})
</script>
Sizing works out of the box. Just set the original inputs class to form-control-sm or
form-control-lg, and
the resulting group gets the class input-group-sm or input-group-lg.
<input class="form-control-sm" type="number" value="0.0" data-decimals="4" min="-1" max="1" step="0.0001"/>
<input class="form-control-lg" type="number" value="1000000" data-decimals="0" min="0" max="2000000" step="1"/>
min, max,
step and data-decimals
const tester = document.getElementById("minMaxTester")
document.getElementById("minInput").addEventListener("change", function (event) {
tester.setAttribute("min", event.target.value)
})
// ...same for max, step, data-decimals
<input data-prefix="$" value="100.0" data-decimals="2" min="0" max="1000" step="0.1" type="number" />
<input data-suffix="°C" value="50" min="0" max="100" type="number" />
This input starts from 0 when reaching 360.
<input step="10" type="number" id="inputLoop" value="0" data-decimals="0" min="-10" max="360"/>
"Loop" the value between 0 and 360 with the input event in JavaScript.
const inputLoop = document.getElementById("inputLoop")
inputLoop.addEventListener("input", function () {
let value = parseInt(inputLoop.value, 10)
value = (value < 0) ? 360 + value : value % 360
inputLoop.setValue(value)
})
An Editor defines how the input is parsed and rendered. The inputSpinner ships some custom Editors in
/src/custom-editors.js, available as named ES exports.
The simplest custom Editor is the RawEditor, it renders just the value and parses just the value,
without any
changes, like a native number input. No internationalization, no digit grouping.
import {InputSpinner} from "./src/InputSpinner.js"
import {RawEditor} from "./src/custom-editors.js"
new InputSpinner(document.getElementById("rawEditor"), {editor: RawEditor})
The TimeEditor renders the number as time in hours and minutes, separated by a colon.
import {InputSpinner} from "./src/InputSpinner.js"
import {TimeEditor} from "./src/custom-editors.js"
new InputSpinner(document.getElementById("timeEditor"), {editor: TimeEditor})
With the templating feature, you can almost do anything, when it comes to layout.
This is the template for "buttons right":
<div class="input-group ${groupClass}">
<input type="text" inputmode="decimal" style="text-align: ${textAlign}" class="form-control"/>
<button style="min-width: ${buttonsWidth}" class="btn btn-decrement ${buttonsClass}" type="button">${decrementButton}</button>
<button style="min-width: ${buttonsWidth}" class="btn btn-increment ${buttonsClass}" type="button">${incrementButton}</button>
</div>
You can... or must use the following variables in your template:
Provide the template as configuration parameter:
new InputSpinner(element, {template: '<div class...'})
To remove the InputSpinner and show the original input element, use
element.destroyInputSpinner()
If you find bugs or have suggestions, you may write an issue.
Run the unit tests in your browser.