Recently I was asked by a client if it would be possible to use a spinbox for a certain value in a web application I was building. Being totally sure this was going to be a piece of cake I said yes (it’s just a textbox with two arrows, right?). As it turns out, it is possible, only a little bit more complicated than I first thought.
The Spinbox

The spinbox is also called spinbutton, spincontrol or UpDown button. You can see it in the picture on the right. It is commonly used to enter, for example, time and dates in desktop applications but isn’t available as an HTML form element.
Placing the arrows
The greatest challenge by far was positioning the arrow images. I started trying to do it using css, but soon gave up when I encountered too many browser inconsistensies, bugs and missing features (such as missing inline-block in Firefox), and decided to do it the old-fashioned way instead: using tables. In my solution, a table is created dynamically around the textbox and made inline so that more than one spinbox can be laid out on the same line. Only problem is, Firefox and IE both don’t understand display:inline-table, they want display:inline instead, which Safari & Opera don’t like. The solution to that:
table.style.display='inline';
try {
table.style.display = 'inline-table';
} catch(e) {}
Firefox just silently drops the inline-table declaration that it doesn’t understand but IE throws and error. That’s why the try/catch statement is needed.
PeriodicalExecuter
When one of the arrows is clicked, the value in the textbox should increase or decrease while the mouse button is held down. To accomplish this I created a Prototype PeriodicalExecuter which updates the textbox with increasing frequency. Only problem is, for some reason they’ve decided to not include a stop method for the PeriodicalExecuter. Luckily, someone else also ran into this problem. I’ve included that solution in my source.
Disable context menu
In Firefox on Mac, the context menu pops up when you hold down the left mouse button for a second or so anywhere in the window. This is obviously a bit annoying when you are trying to use the spinbox. Turns out that you can stop it from happening by denying the onContextMenu action from firing. In Prototype code:
Event.observe(img,'contextmenu',function(evt){Event.stop(evt);});
In HTML this would be:
<img src="pic.gif" oncontextmenu="return false;">
Files
Download the files here: tesSpinbox.
You can try a live demo here: Demo.
Usage
Include prototype first, and then spinbox.js. Change the path to the images in spinbox.js (sb_imgpath) to point to where you uploaded the images.
Then to convert any textbox into a spinbox:
new SpinBox(id_of_textbox,min_value,max_value,padded_length);
Padded_length is the desired length of the string in the textbox. If the string is shorter than this value, it will be padded with zeros. A padded_length of 3 would mean that 7 becomes 007, for example.
A spinbox example:
<input type="text" id="myspin" size="2">
<script language="javascript">
new SpinBox('myspin',0,59);
</script>
Will turn the textbox into a spinbox with a minimum value of 0, maximum value of 59 which is not zero-padded at all.