JSFiddle - React, Tailwind, and code Playground

by allcaps

HTML

<label for="foo">Foo</label>

<input id="foo" type="text" min="1" value="36" autocomplet="off" />

<span>
    <a class="add"></a>
    <a class="subtract"></a>
</span>

<select>
    <option>9</option>
    <option>12</option>
    <option>18</option>
    <option>36</option>
    <option>72</option>
    <option>144</option>
</select>
<p>How to change the value (ltr):</p>
<ul>
    <li>Click the label and type (selects all).</li>
    <li>Click up or down button (adds or subtracts 1).</li>
    <li>Click up or down button while hoding shift (adds or subtracts 10).</li>
    <li>Hover over the input and scroll (adds or subtracts some).</li>
    <li>Hover over the input and scroll while holding shift (adds or subtracts many).</li>
    <!-- TODO: <li>Click the input and scroll while NOT hovering.</li>-->
    <li>Click the label or input and type 'Math.E * Math.PI' or '9*12'and enter (Evaluates JS... Should be restricted to some simple operators).</li>
    <li>Input 9, 12, 18, 36, 72 or 144 (Updates the selected option in the selector).</li>
    <!-- TODO: The selected option get's updated only on manual input. Update on any change. -->
    <li>Click the input and press arrow keys (add or subtract 1).</li>
    <li>Click the input and press arrow keys while holding shift (add or subtract 10).</li>
    <li>Use the option selector.</li>
</ul>

CSS

label {
    font-family: sans-serif;
    font-size: .8em;
    color: #444;
}
span {
    display: inline-block;
    width: 19px;
    height: 19px;
}
a {
    text-decoration: none;
    width: 19px;
    height: 10px;
    display:block;
    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAATCAMAAADLVI+CAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCMDYxRjhFNUI5RkUxMUU0ODQ3MUZBNEI0REFGREY3OSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCMDYxRjhFNkI5RkUxMUU0ODQ3MUZBNEI0REFGREY3OSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkIwNjFGOEUzQjlGRTExRTQ4NDcxRkE0QjREQUZERjc5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkIwNjFGOEU0QjlGRTExRTQ4NDcxRkE0QjREQUZERjc5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+8vkAtwAAAFdQTFRF4uLi+fn5vLy88PDwzMzMU1NT9vb27u7u1dXVtLS0Li4ucHBwCQkJMjIyMDAwCAgIWVlZz8/Pzs7O6+vr7e3tm5ubqqqqsbGxq6ur5+fn7Ozs9PT0ra2tgj7kngAAAJhJREFUeNqU0ssWgyAMRdGowUcLGsBn2///zuoAl9wMWs94QzIIRc95Ia5i8mSlMBZ5o5eF8hYhBlXUbEBRa24zp5nVzDmHzFqLzLnkTmZtcjd2q6E3mxbaHz51Dx1xA73YdNBnH1pBDZsS6k7WH+VsOAJWJXX5Lakrq3o9dCg1+2u3X8xvwLYgE7BJKAa4Xh9ndb3zV4ABALdKDTNFPtJRAAAAAElFTkSuQmCC');
}
.add {
    margin-top: 5px;
}
.subtract {
    height: 9px;
    background-position: 0 -10px;
}
a:active {
    background-position: -19px 0;
}
a.subtract:active...

JavaScript

var form = $('form');
var label = $('label');
var add_button = $('.add');
var subtract_button = $('.subtract');
var select = $('select');
var input = $('input');

label.click(function (e) {
    input.select();
});

add_button.click(function (e) {
    var n = input.val();
    var x = 1;
    if (e.shiftKey) {
        x = 10;
    }
    input.val(Math.max(parseInt(n) + x, 1));
});

subtract_button.click(function () {
    var n = input.val();
    var x = 1;
    if (event.shiftKey) {
        x = 10;
    }
    input.val(Math.max(parseInt(n) - x, 1));
});

select.change(function () {
    var n = $(this).val();
    input.val(n);
});

input.change(function () {
    var n = $(this).val();
    // TODO: Eval is evil. Maybe http://jsfromhell.com/classes/math-parser
    n = eval(n);
    $(this).val(Math.max(n, 1));
    
    // Set the option list value
    var n = $(this).val();
    if ($.inArray(n, [9, 12, 18, 36, 72, 144])) {
        select.val(n);
    } else {
        select.val('');
    }
});

input.bind('mousewheel', function (e) {
    e.preventDefault();
    var n = $(this).val();
    var x = 1;
    if (e.shiftKey) {
        x = 10;
    }
    if (e.originalEvent.wheelDelta / 120 > 0) {
        $(this).val(Math.max(parseInt(n) - x, 1));
    } else {
        $(this).val(parseInt(n) + x);
    }
});


input.keydown(function (e) {
    var n = $(this).val();
    var x = 1;
    if (e.shiftKey) {
        x = 10;
    }
    switch (e.which) {
        // case 37:
            // left
        //    $(this).val(Math.max(parseInt(n) - x, 1));
        //    break;
        case 38:
            // up
            $(this).val(parseInt(n) + x);
            break;
        //case 39:
            // right
        //    $(this).val(parseInt(n) + x);
        //    break;
        case 40:
            // down
            $(this).val(Math.max(parseInt(n) - x, 1));
            break;
        default:
            return; // exit this handler for other keys
    }
    e.preventDefault(); // prevent the...