I recently wanted to fix a few bugs within last years slider experiment but, as my coding style has changed so dramatically over the past year (believe me, I’ve learned a lot in the past year and find it hard to even look at my old code), I ended up rewriting the entire thing from scratch.
This gave me the opportunity to make the code more robust, fix the aforementioned bugs and add some nice shiny new features into the mix.
In brief…
- Conforms to the WAI-ARIA defined role of “slider”
- More robust Javascript code written to current “best practices”
- Both the slider’s range and increment can accept positive or negative values
- Both the range and the increment can be set to Float or Integer values
- A second “maximum increment” can be defined to use for mouseWheel and keyboard events
- mouseWheel support can be disactivated on a full-page or individual slider basis
- Callback functions can now be defined for the update, create, destroy, redraw and move events
- Skinnable using only CSS i.e. there are no messy in-script image paths to edit
The impatient amongst you may wish to have a quick look at the available demos before reading any further.
Configuring the slider
Sliders can be associated with both text input and select list form elements. All of the slider’s configuration parameters should be defined within the associated form element’s className as described below.
Stipulating the slider’s numeric range
If using a select list as the slider’s associated form element, it is not necessary to set a range (as the script will calculate this automatically by using the number of options present within the select list itself). You are however required to add the class fd_slider to the select list’s className.
If using a text input, add the class fd_range_limit1_limit2 to the associated input’s className, where limit1 and limit2 are replaced with the numeric values you wish the slider to use e.g. the class ‘fd_range_-255_255’ will give the slider a numeric range of -255 to 255. This is a required class – without it, no slider control is created for text input elements. The limit1 is displayed to the left of horizontal sliders and the top of vertical sliders and limit2 to the right of horizontal sliders and the bottom of vertical sliders – this enables you to have inversed ranges as shown within the vertical slider demo.
Should you wish to stipulate a range containing decimal places, just use the format fd_range_XXdYY_XXdYY, where XX represents the integer part and YY the decimal part. The literal character d is required and gets converted to a decimal point automatically by the script e.g. the classname ‘fd_range_-20d2_20d2’ will give the slider a numeric range of -20.2 to 20.2.
If no range is stipulated, it automatically defaults to the values 0 – 100.
The slider’s numeric increment
Sliders associated with a text input can also have an increment stipulated by using a class of the form fd_inc_XX where XX represents the increment to use. As with the range, the increment can also contain decimal places e.g. the class fd_inc_0d20 will set an increment of 0.2 and the class fd_inc_40 an increment of 40.
Decimal place precision
Additionally, the number of decimal places used to format the associated input element’s return value is calculated by using the number of decimal places stipulated within the increment e.g. the class fd_inc_0d400 will set an increment of 0.4 and set the result to have three decimal places (as there are three characters after the decimal point e.g. “400”) whereas the class fd_inc_0d4 will still set an increment of 0.4 but set the result to have just one decimal place (as there is only one character after the decimal point e.g. “4”). An example of using decimal values for both the range and increment and also stipulating the return value precision can be seen within the vertical slider demo.
If no increment is set, the script defaults to using a value of 1.
MouseWheel and keyboard event increments
The slider can now use a different increment when reacting to both mouseWheel and keyboard events. This is stipulated in an identical fashion to the normal increment but uses the class fd_maxinc_XX, where XX again represents the decimal/integer value of the increment.
If no fd_maxinc_XX class is located, the script defaults the maximum increment to double the value of the normal slider increment.
MouseWheel support
Once a slider has focus, the mouseWheel can be used to move the slider handle. The slider handle will move by the maximum increment (fd_maxinc) should one have been defined or by two times the normal increment if no fd_maxinc was defined.
Disabling mouseWheel support
MouseWheel support can be disabled for all sliders appearing on the same page or on an individual basis.
Disabling mouseWheel support for all sliders
MouseWheel support can be disabled for all sliders appearing on the same page by calling the fdSliderController.disableMouseWheel() method after the script has been included in your page. An example of this is shown below:
<script type="text/javascript" src="the/path/to/slider.js">
</script>
<script type="text/javascript">
//<![CDATA[
// Disable the mouseWheel support for all sliders on the page
fdSliderController.disableMouseWheel();
//]]>
</script>
Disabling mouseWheel support for individual sliders
To disable the mouseWheel for individual sliders, just add the class fd_disable_mousewheel to the associated form element’s className.
The available handle animation effects
Whenever a user clicks on the slider bar (not the slider handle), there are three possible effects that can be used:
The “animated tween” option
Should the associated form element’s className contain fd_tween, clicking on the slider bar initiates a tween animation that scrolls the slider’s “drag-handle” to the point in which the mouseDown event occurred (to be more precise, it scrolls the handle to the nearest “exact value” point).
The “jump to value” option
Should the associated form element’s className contain fd_jump, clicking on the slider bar immediately moves the slider’s “drag-handle” to the point in which the mouseDown event occurred (again, to be more precise, the handle jumps to the nearest “exact value” point).
The “timed scroll” option
Should none of the above two classes be located, the slider defaults to scrolling the slider drag-handle by the defined maximum increment (fd_maxinc) in the direction of where the mouseDown event occurred.
An example of each type of animation effect can be seen within the handle movement demo.
Callback functions
Callback functions can now be defined for the update, create, destroy, redraw and move events.
To stipulate a callback function, give the associated input a class of the form fd_slider_cb_callbackType_callbackFunctionName e.g. the class ‘fd_slider_cb_update_updateColor’ will get the slider to call the javascript function ‘updateColor()’ each time the associated form element’s value is changed and the class ‘fd_slider_cb_move_positionTooltip’ will get the slider to call the javascript function ‘positionTooltip()’ each time the slider’s handle moves.
Multiple callback functions can be declared for the same event by repeating the class e.g. the class “fd_slider_cb_update_updateFunc1 fd_slider_cb_update_updateFunc2” will tell the slider to call the functions “updateFunc1()” and “updateFunc2()” whenever the update event fires. When multiple functions are defined for the same event, they are called in the order in which they were defined.
A quick word on callback function names
As callback function names are being declared within a CSS className, the function name itself is limited to the set of alphanumeric characters valid for use within such a CSS className i.e. while the character “$” is a valid JavaScript function name, it is not a valid character for use within a CSS className and so should be avoided.
Stipulating an Object.method as a callback function
It is now possible to stipulate an object method as a callback function. Object.methods can be stipulated by converting the “dots” (i.e. the full-stops) to minus signs (-); for example, the className “fd_cb_update_myObject-myMethod” will tell the script to call the “myMethod” method of the JavaScript Object “myObject” e.g. myObject.myMethod();
The callback function data object
All callback functions are passed an object of the form:
{
elem:[the slider's associated form element],
value:[the associated form element's current value]
}
Hiding the associated form element
Giving the form element a class of fd_hide_input will do exactly that, and hide the associated element on slider creation (the default functionality is to keep the form element visible).
Form elements are hidden by giving them the class “fd_hide_slider_input”. Currently, this class just sets the element’s display property to “none” and so the value will still be submitted to the server – unfortunately, setting an element to display “none” makes it unavailable to some assistive technologies, and until assistive technology can use the ARIA information sent by the browser, it is recommended that you keep the input displayed.
Alternatively, you can change the “fd_hide_slider_input” class definition to use absolute positioning as described within the webAIM article CSS in Action: Invisible Content Just for Screen Reader Users.
Creating vertical sliders
Vertical sliders can be created by adding the class fd_vertical to the associated form element’s className.
Styling the slider
Sliders can have additional classes given to them (to enable you to style them differently to the others) by adding classes of the form fd_slider_cn_yourclassnamehere to the associated form element’s className e.g. the class ‘fd_slider_cn_hunkydory’ will give the associated slider control an extra class of ‘hunkydory’.
Additionally each slider control is given a unique ID of the form ‘fd-slider-theAssociatedInputElementsId’. This enables you to target individual sliders within the CSS and also enables DOM access to the top level slider div by using document.getElementById.
The dynamically created HTML
The following HTML is used to create the slider:
<div id="fd-slider-[form element id]"
class="fd-slider [extra classes]">
<span class="fd-slider-inner" />
<span class="fd-slider-bar" />
<button id="fd-slider-handle-[form element id]"
class="fd-slider-handle"
type="button"
role="slider"
aria-valuemin="[minimum value]"
aria-valuemax="[maximum value]"
aria-labelledby="[form element's label]"
aria-describedby="fd_slider_describedby"
aria-valuenow="[current value]"
aria-valuetext="[current textual value]">
</button>
</div>
Note: The “aria-describedby” relationship is only set if the document contains an element with an id of “fd_slider_describedby”. When using a select list as the associated form element, the “aria-valuetext” is set to the currently selected option’s textual value and the “aria-valuenow” to the same option’s value.
Keyboard accessibility and ARIA roles & states
Once a slider has focus, the arrow keys can be used to move the drag handle, the Home button to move the slider to it’s minimum value and the End button to move the slider to it’s maximum value. Pressing the CTRL key and an arrow key will move the slider handle by increment defined within the fd_maxinc class (or by two times the normal increment should no fd_maxinc be defined).
Each slider is given the WAI-ARIA role of slider and it’s associated states valuemax, valuemin, valuetext (for sliders created from selectlists) and valuenow.
Should an element with an id of fd_slider_describedby exist within the DOM, this is used to set the ARIA describedby relationship.
Additionally, should the slider’s associated form element itself have an associated label, this label is used to set the ARIA labelledby relationship.
Backwards compatibility
By default, the slider handle is created from a BUTTON element which makes it keyboard accessible across all current browsers (as BUTTON elements are “focusable” and automatically become part of the document’s tab order by default).
If you wish to use a pure ARAI solution i.e. one that entails programmatically setting a tabIndex on a non “focusable” element, give the slider’s associated form element the class fd_full_aria; this will instruct the script to construct the slider handle from a SPAN, not BUTTON element and programmatically place the SPAN into the document’s tab order. The latest versions of all current A-grade browsers support programmatically setting the tabIndex on non-focusable elements and so this option has a more widespread reach than was possible even six months ago.
The available slider A.P.I methods
The following methods have been made available from the fdSliderController Object:
| Method | Description |
|---|---|
create( [form element] ) |
When a form element is passed into the function, the script will recreate the slider for the element in question. Should no form element be passed in, the script will rescan the entire document and recreate all of the required sliders. |
destroyAll |
When called, this method will destroy all current sliders |
destroySlider( id ) |
This method will destroy the slider associated with the form element id that was passed as an argument |
increment( elemID, numberOfSteps ) |
This method increments the slider associated with the input whose id attribute is elemID by the number of steps provided by the second argument. Negative increments can be defined. |
disableMouseWheel( ) |
This method will disable mouseWheel support for all sliders on the current page. |
removeOnLoadEvent( ) |
This method will remove the onload event for the sliderController meaning you have to manually call the init method. Useful if you use a “onDomContentLoaded” function etc. |
addEvent(elem, eventType, function), removeEvent(elem, eventType, function) and stopEvent(event) |
Common event management functions |
For example, to use the create method, you would call fdSlidercontroller.create().
Bugs and annoyances
Opera
Opera fires the blur event onmouseup which means I have to programmatically reset the focus, this causes a slight “flicker” as the styles are swapped (and I hope assistive technologies are savvy enough to report this focus event to the user).
Safari
Safari only calls the focus event handler on keyboard, not mouse events, which again means I have to programatically set the focus.
Internet Explorer
The demo uses png images for the slider drag-handles (originally located at schillmania) and will therefore only display in Internet Explorer (5.5 & 6) by using additional and proprietary CSS filter behaviours (which are passed using conditional comments within the demo). All other modern browsers display the png images as intended.
Future development
Future versions of the slider will:
- Integrate an optional system for rendering the slider scale
Give you an easier method for globally disabling mouseWheel eventsUse the page up and page down keys as advised in the AOL authored DHTML Style GuideWill use a className (and not a JavaScript initiated “display:none“) to hide the associated form element – enabling you to choose the method appropriate for your project- Ship with different themes that (where possible) scale to fit liquid layouts
The License
The script is released under a creative commons Attribution-Share Alike 3.0 Unported license. Should you use the script within a commercial context please think about clicking the payPal donate button – it’s certainly not an obligation but it would most certainly put a smile on my face. If you need a dual license, just ask me politely.
References
If you’ve read this far, you may also be interested in the following:
- The WAI-ARIA roadmap
- A List Apart’s primer on Accessible Web 2.0 Applications with WAI-ARIA
- Juicy Studio’s WAI-ARIA in HTML article and slider control demo
- schillmania, where the slider styles and png images were originally located
- Mouse wheel programming in JavaScript, general information about handling mouse wheel-generated events in JavaScript programming language
- The webAIM article “CSS in Action: Invisible Content Just for Screen Reader Users“
Demo, Downloads and Updates
Tested in Internet Explorer 6, Opera 9.5, Safari 3 (Win & Mac) and Firefox 3 (Win).
View the basic slider demo (that demo’s the three different handle animation effects), the tooltip demo (that creates a tooltip to display the slider’s current value), the colour picker demo (that uses three sliders to create a colour picker), the alternative styling demo (that styles the sliders differently), the vertical slider demo (that demo’s a vertical slider and a return value set to have a precision of two decimal places) or the increment demo (that shows how to extend the slider functionality using the increment A.P.I. method). Download a .zip of the demo source, download a 17k YUI minified version of the script or have a look at the uncompressed javascript code.
17/10/2008 (v2.4):
- Changed the parseCallbacks function to use Function.apply. Code graciously sent by Artem B.
- Added the Ins and Del keyboard events
13/10/2008 (v2.3):
- Moved the slider into the controller’s scope
- Added the Page up and Page down keyboard events
- Inputs are now “hidden” by being given the class “fd_hide_slider_input”
23/09/2008 (v2.2):
- Fixed a bug in the tooltip demo
- Fixed a bug within the key event code
- Added a minified version to the download
07/08/2008 (v2.1):
- Added the disable mouseWheel functionality
01/08/2008 (v2.0):
- Creation

Previous Comments ~
Nice work, Brian. I like what you’ve done with this slider and I’m using your tooltip-enabled slider on a form on our intranet. In internal feedback some users wondered if we might improve usability by disabling the scrollwheel function. And indeed, after playing around with our form some more, I’ve begun to agree. Most users will have their scrollwheel set to scroll the page, and when they activate the slider and then use the mouse pointer to move the slider, then their next instinct may be to use the scrollwheel to scroll to the next question on the form. If instead the scrollwheel suddenly causes their selected value to move, then they may be momentarily disoriented. And it is a bit awkward that the only way to stop the scrollwheel from scrolling the select value is to click outside the slider area. A nice addition to your excellent code might be to include an on/off flag for the scroll wheel function to make it easy to turn it off in slider.js.
@ Philip: Hi Philip, good improvement! I’ll add a variable to the script that you can enable/disable. I’ll attempt to get it done a.s.a.p..
Thanks for the feedback,
Brian
Hello any plans for making it work with dual handles? I really miss that :(
Or is there a easy way to hack to script and add it my self?
@ Arnout: Hi Arnout, I’m afraid the currently in-vogue “double handle” would require a substantial change to the script (and also require two associated form elements to return the results) – which, of course, I just haven’t the time to complete. Perhaps in a future iteration of the script.
Regards,
Brian
Hi i really like this script, you must have put in alot of hard work.
I was trying to work out how to call a function when the mouse button is released i have a little javascript knowledge but not alot, im trying to build a jumpmenu.
i was thinking it would be in onmouseup event but im struggling to get the updated value.
Then i thought i could call it from the class cb for example fd_slider_cb_create_geturl fd_slider_cb_mouseup_geturl which would then call a function called geturl.
could you point me in a right direction?
Thanks
C
@ Charlie: Hi Charlie, have a look at the code of the toolTip demo, it adds both blur and focus event handlers to the handle. Here’s how you might just do it for an associated form element with an id of “selectTest1” for the mouse events you require (remember to add fd_slider_cb_create_addBespokeHandleEvents to the form element className):
Regards,
Brian
woo hoo! works really great :)
Thank you for your reply
Charlie
It was only early August – a week and a few days ago. After some desperate Googling, I’ve found your site and your wonderful script. It was everything the site I was working on needed, with support for scroll wheels, keyboard keys and mouse click-dragging, when YUI has failed on me – (begin YUI rant) when both onContentReady (placed on the global header of every page the site I was working on, which I cannot change) and onDOMReady (required by YUI’s Slider control) exists on the same page, the Slider never gets initalized. (end YUI rant)
With some (rushed) modifications, I have turned v2.0 of this brilliant Slider Control into a vertical scroll bar, and it has been live on TVB Hong Kong’s Beijing 2008 Olympics website for a few days, serving thousands of thousands of users each day during this year’s Olympic Games.
http://beijing2008.tvb.com/schedule/
I tried to note every line I’ve modified in the source code, but I might have missed some during moments when a urgent bugfix was needed. And you’ll notice some sloppy coding here and there, especially parts involving the slider’s direction, but I did not have enough time to fully understand your code.
Thank you for writing this amazing script. It has saved me from lots of stress and frustration trying to figure out what’s going on with YUI’s Slider or to convince my boss to remove the onContentReady code in the site’s global header. If your site had a PayPal donate button, I might have donated my pay to you back then!
During the coming few weeks (or months), in my free time, I’ll reimplement the changes (mainly the ability to invert the slider) I’ve done to your script properly sans sloppy coding, and fully contribute it to you for distribution, to comply with the Creative Commons Attribution-ShareAlike license.
Thank you, thank you,
Phil
@ Phil: Hi Phil, it’s always nice to see a script out in the wild! Thanks for the info and I’m glad to have been of service.
Ok brian,
ill wait :)
I have been trying to work with the vertical slider and I am having some issues. This is how I am defining it:
[open-tag]input type=“text” maxlength=“3” class=“fd_vertical fd_hide_input fd_slider_cb_create_Slider-init fd_slider_cb_update_Slider-update fd_jump fd_range_0d65_1d15 fd_inc_0d05 fd_maxinc_0d05” title=“Slider Range” value=“0.75” id=“sizeSlider” name=“slider”/ [close-tag]
The callbacks are working as expected. The range is working as well as the inc definition, but the maxinc does not seem to be working. Also, the values for the slider seem to be upside down. It initially loads in the right place (just down from the top), but as soon as you change it, the values show as if they are largest at the top and smallest at the bottom. Also, the mouse scroll is backwards (may be due to the values being flipped).
How can I go about fixing this?
Thanks for the great work…
i have switched to the select version so i can order the way i would like etc… i have most everything working except for the initial placement of the slider. for example, if i have the values 1, 2, ... , 9, 10 and i have the initial value set to 3, the slider will actually be set at 7. once i move the slider, the placement is correct, its only the initial placement that is being put at the wrong end of the slider. any suggestions???
Update by f.d: Will, check your mail!
@ Will: Hi Will, I’m just about to leave for the airport and won’t be back until Wednesday 27th. I’ll have a look at the issue for you when I get back.
Regards,
Brian
Congratulations, you’ve done a great work.
However the licence you’ve choosen makes it difficult to integrate it into GPLed opensource softwares.
At least with version 2.0 of CC-BY-SA (http://www.gnu.org/licenses/license-list.html#GPLIncompatibleLicenses)
Have you considered a dual licencing in order to have your Slider integrated in GPLed softwares ?
Regards,
Thibault
Hi, Brian!
Thanx for this excellent script! I have added a small modification to your parseCallbacks function to support methods invocations. I have also removed the “eval” because it has a performance penalty. You may consider adding the modification to your original script. Here is the URL: http://artemb.info/files/modifiedParseCallbacks.js
—
With best regards,
Artem.
@ Thibault: Hi Thibault, mail me: brian at google’s nice email application.
@ Artem: Hi Artem, the code already handles object.method calls (such as anObject.testMethod() etc) – as can be seen within the increment demo. As for the eval, it’s ran only once (per callback) so shouldn’t affect performance to a noticeable degree (and yes, I understand that people find the eval statement distasteful).
If I’m wrong in my assumption that all object.method calls work, don’t hesitate to tell me!
Thanks for the comment,
Brian
Hi, Brian!
Your code handles methods as functions in a namespace. If a method relies on the fact that it is a part of an object (uses “this”), it fails. You need to apply a function to an object for it to work as a method and not as a function.
I’m also working on an optional logarithmic scale for your sliders. If you wish, I can share the code too.
@ Artem: Hi Artem, thanks for the code, I’ve added a slightly modified version to the release.
@ Thibault: Hi thibault, mail me for an alternative license. Brian at google’s email application. Thanks.
Great applet, this definately deserves donation
, can you please private email me with a suitable amount? and paypal details (When I click on paypal icon, it’s French..I’d like to pay from paypal US account).
Thank you.
@ vin: Hi Vin, you can connect to your U.S. account even from the French version of the PayPal site but… don’t worry about it. Only do it if your feeling generous today!
P.S. It’s not an applet, it’s plain old JavaScript.
hi – these slidebars are brilliant. a was curious if there’s a way to assign a maximum to the total of say 4 sliders and then adjust each slider automatically when one is changed. anyone know if that’s at all possible?
@ sc: Hi sc, you would need to write a callback function (shared between all four sliders) that reset the (three remaining sliders) associated input’s value. Quick question though: Say I’m dragging the top slider and have just depassed the allowed total maximum value – what slider gets it’s value decremented? or are the other 3 sliders decremented by an equal amount i.e. (currentTotal – maxTotal) / 3
Regards,
Brian
I am trying to have more than one slider on the same page, but the tooltip seems to be dependent on a long javascript and I find no way to have it working on all the sliders at the same time.
Which part should I duplicate/alter, please?
@ Luigi: Hi Luigi, the tooltip demo is just there to show you how you might extend the slider functionality. It’s not supported in any way – but check your mail as I’m in a helpful mood today and I’ve sent you an updated demo that can deal with reusing the same tooltip for multiple sliders.
hi excellent work, but i get error when trying to apply any hind of mouseup event to the slider control.
with this code:
fdSliderController.addEvent(jQuery(”#fd-slider-trans”),“mouseup”,submitupdate);
i can only ever seem to get it to work on the document and thats it
thanks
@ Dave: Hi Dave, what’s the errors exactly? Why don’t you try attaching to the blur & focus events instead (as the handle is given a tabIndex and therefore reacts to these events).
Regards,
Brian.
Hi Brian,
I have just started an open source project using your accessible slider as one of the components. The project is a jquery-based audio player.
This is to say thanks for your work, and to let you know I have added
some new features (in case you want to grab the code). They are:
* keyboard nudge of slider can be set to different amounts to normal
inc. I set the number of steps on the slider to seconds – this enables
screen readers to nudge by (in my case) 5 or 30 seconds at a time.
* dynamically update the number of steps in the slider. The player will eventually have a playlist, so the number of steps needs to change to match the duration as each audio clip plays.
* refresh. I change the value of the input box based on an event from the player timer that says what time the player is up to. This causes the slider to update (my update did not trigger an internal event to do this).
The project is hosted on github (the first of the above features is not
in the public repo yet).
http://github.com/rhulse/audio-player/wikis
cheers,
Richard
@ richard: Hi Richard, good to hear someone’s actually using the code – it’s this sort of thing that makes me want to continue writing the Lab scripts!
You can set a different keyboard increment by using the “fd_maxinc_XX” className but this is an increment shared between the keyboard and mousewheel so it might not be the optimal solution in your case.
I’ll be keeping an eye on the project and thanks for letting me know about it.
Regards,
Brian