noUiSlider Slider range and handles Reading & Setting values Options Tapping, dragging & fixed ranges Examples Events Scale/Pips More... Download noUiSlider
§

Colorpicker

We'll initialize all sliders with the same options, and use the slide callback to keep to color in sync with the slider values. This callback fires when the slider is moved by sliding, or when it is clicked or tapped.

The HTML
<div id="colorpicker">
	<div class="sliders" id="red"></div>
	<div class="sliders" id="green"></div>
	<div class="sliders" id="blue"></div>

	<div class="result"></div>
</div>
The setColor function
function setColor(){

	// Get the slider values,
	// stick them together.
	var color = 'rgb(' +
		sliders[0].noUiSlider.get() + ',' +
		sliders[1].noUiSlider.get() + ',' +
		sliders[2].noUiSlider.get() + ')';

	// Fill the color box.
	resultElement.style.background = color;
	resultElement.style.color = color;
}
Initializing the slider
var resultElement = document.getElementById('result'),
	sliders = document.getElementsByClassName('sliders');

for ( var i = 0; i < sliders.length; i++ ) {

	noUiSlider.create(sliders[i], {
		start: 127,
		connect: "lower",
		orientation: "vertical",
		range: {
			'min': 0,
			'max': 255
		},
		format: wNumb({
			decimals: 0
		})
	});

	// Bind the color changing function
	// to the slide event.
	sliders[i].noUiSlider.on('slide', setColor);
}
CSS
#red, #green, #blue {
	margin: 10px;
	display: inline-block;
	height: 200px;
}

#colorpicker {
	height: 240px;
	width: 310px;
	margin: 0 auto;
	padding: 10px;
	border: 1px solid #BFBFBF;
}

#result {
	margin: 60px 26px;
	height: 100px;
	width: 100px;
	display: inline-block;
	vertical-align: top;
	color: rgb(127, 127, 127);
	background: rgb(127, 127, 127);
	border: 1px solid #fff;
	box-shadow: 0 0 10px;
}

#red {
	background: #c0392b;
}

#green {
	background: #27ae60;
}

#blue {
	background: #2980b9;
}
§

Custom connect

When using the connect option, noUiSlider paints the connecting bar in the negative space between handles. This uses one less element and has some nice performance benefits. When you need more control over the connecting option, you can create a custom connecting bar using the update event.

This custom element can be styled, or special features (like requested in this issue) can be implemented.

Create the slider
var connectSlider = document.getElementById('connect');

noUiSlider.create(connectSlider, {
	start: [20, 80],
	connect: false,
	range: {
		'min': 0,
		'max': 100
	}
});
Create a connecting bar and bind it
var connectBar = document.createElement('div'),
	connectBase = connectSlider.querySelector('.noUi-base');

// Give the bar a class for styling and add it to the slider.
connectBar.className += 'connect';
connectBase.appendChild(connectBar);

connectSlider.noUiSlider.on('update', function( values, handle, a, b, handlePositions ) {

	var offset = handlePositions[handle];

	// Right offset is 100% - left offset
	if ( handle === 1 ) {
		offset = 100 - offset;
	}

	// Pick left for the first handle, right for the second.
	connectBar.style[handle ? 'right' : 'left'] = offset + '%';
});
CSS for the connecting bar
/* For this slider, disable the 'origin' size. */
#connect .noUi-origin {
	right: auto;
	width: 0;
}

/* Position the bar and color it. */
#connect .connect {
	position: absolute;
	top: 0;
	bottom: 0;
	background: #80C9F5;
	box-shadow: inset 0 0 3px rgba(51,51,51,0.45);
}

/* When the slider is moved by tap,
   transition the connect bar like the handle. */
#connect.noUi-state-tap .connect {
-webkit-transition: left 300ms, right 300ms;
	transition: left 300ms, right 300ms;
}
§

Using HTML5 input elements

noUiSlider is perfectly fine serializing values to any element with a .val() method, so lets try using type="number" and <select>.

Note that if your browser doesn't support an input type, it will just assume "text". If you'd like to know more, consider reading this article.

We'll append <option> elements to the <select> dynamically.

Appending <option> elements
var select = document.getElementById('input-select');

// Append the option elements
for ( var i = -20; i <= 40; i++ ){

	var option = document.createElement("option");
		option.text = i;
		option.value = i;

	select.appendChild(option);
}
Initializing the slider
var html5Slider = document.getElementById('html5');

noUiSlider.create(html5Slider, {
	start: [ 10, 30 ],
	connect: true,
	range: {
		'min': -20,
		'max': 40
	}
});
Linking the <select> and <input>
var inputNumber = document.getElementById('input-number');

html5Slider.noUiSlider.on('update', function( values, handle ) {

	var value = values[handle];

	if ( handle ) {
		inputNumber.value = value;
	} else {
		select.value = Math.round(value);
	}
});

select.addEventListener('change', function(){
	html5Slider.noUiSlider.set([this.value, null]);
});

inputNumber.addEventListener('change', function(){
	html5Slider.noUiSlider.set([null, this.value]);
});
Example CSS
#input-select,
#input-number {
	padding: 7px;
	margin: 15px 5px 5px;
	width: 70px;
}
§

Non linear slider

One of noUiSlider's core features is the ability to divide the range in a non-linear fashion. Stepping can be applied, too! The example on the right shows where the handles are on the slider range in values and percentages.

Setting up the slider
var nonLinearSlider = document.getElementById('nonlinear');

noUiSlider.create(nonLinearSlider, {
	connect: true,
	behaviour: 'tap',
	start: [ 500, 4000 ],
	range: {
		// Starting at 500, step the value by 500,
		// until 4000 is reached. From there, step by 1000.
		'min': [ 0 ],
		'10%': [ 500, 500 ],
		'50%': [ 4000, 1000 ],
		'max': [ 10000 ]
	}
});
Read the slider value and the left offset
// Write the CSS 'left' value to a span.
function leftValue ( handle ) {
	return handle.parentElement.style.left;
}

var lowerValue = document.getElementById('lower-value'),
	lowerOffset = document.getElementById('lower-offset'),
	upperValue = document.getElementById('upper-value'),
	upperOffset = document.getElementById('upper-offset'),
	handles = nonLinearSlider.getElementsByClassName('noUi-handle');

// Display the slider value and how far the handle moved
// from the left edge of the slider.
nonLinearSlider.noUiSlider.on('update', function ( values, handle ) {
	if ( !handle ) {
		lowerValue.innerHTML = values[handle] + ', ' + leftValue(handles[handle]);
	} else {
		upperValue.innerHTML = values[handle] + ', ' + leftValue(handles[handle]);
	}
});
§

Locking sliders together

Two cross-updating sliders can be created using a combination of the change and slide events.

Setup and button clicks
// Store the locked state and slider values.
var lockedState = false,
	lockedSlider = false,
	lockedValues = [60, 80],
	slider1 = document.getElementById('slider1'),
	slider2 = document.getElementById('slider2'),
	lockButton = document.getElementById('lockbutton'),
	slider1Value = document.getElementById('slider1-span'),
	slider2Value = document.getElementById('slider2-span');

// When the button is clicked, the locked
// state is inverted.
lockButton.addEventListener('click', function(){
	lockedState = !lockedState;
	this.textContent = lockedState ? 'unlock' : 'lock';
});
The Crossupdate function
function crossUpdate ( value, slider ) {

	// If the sliders aren't interlocked, don't
	// cross-update.
	if ( !lockedState ) return;

	// Select whether to increase or decrease
	// the other slider value.
	var a = slider1 === slider ? 0 : 1, b = a ? 0 : 1;

	// Offset the slider value.
	value -= lockedValues[b] - lockedValues[a];

	// Set the value
	slider.noUiSlider.set(value);
}
Initializing the sliders
noUiSlider.create(slider1, {
	start: 60,

	// Disable animation on value-setting,
	// so the sliders respond immediately.
	animate: false,
	range: {
		min: 50,
		max: 100
	}
});

noUiSlider.create(slider2, {
	start: 80,
	animate: false,
	range: {
		min: 50,
		max: 100
	}
});

slider1.noUiSlider.on('update', function( values, handle ){
	slider1Value.innerHTML = values[handle];
});

slider2.noUiSlider.on('update', function( values, handle ){
	slider2Value.innerHTML = values[handle];
});
Linking the sliders together
function setLockedValues ( ) {
	lockedValues = [
		Number(slider1.noUiSlider.get()),
		Number(slider2.noUiSlider.get())
	];
}

slider1.noUiSlider.on('change', setLockedValues);
slider2.noUiSlider.on('change', setLockedValues);

// The value will be send to the other slider,
// using a custom function as the serialization
// method. The function uses the global 'lockedState'
// variable to decide whether the other slider is updated.
slider1.noUiSlider.on('slide', function( values, handle ){
	crossUpdate(values[handle], slider2);
});

slider2.noUiSlider.on('slide', function( values, handle ){
	crossUpdate(values[handle], slider1);
});
§

Changing the slider by keypress

To keep the library small, features like keyboard interaction haven't been included. However, adding features to input fields linked to a slider is easy. noUiSlider provides API's to help you. In this example, pressing the keyboard arrow keys will increase/decrease the slider by one step.

This example uses the 'step' API to determine by how much the slider should be changed. You don't need this function if your slider is linear. In that case, increase/decrease the value with the ammount of your step.

We'll listen to keydown on the '#input-with-keypress' element, and pass the event to a function so we can read the code that identifies the key.

Note that the slider value will be a string, so we'll need to parse it to an integer.

Initializing the slider and linking the input
var keypressSlider = document.getElementById('keypress'),
	input = document.getElementById('input-with-keypress');

noUiSlider.create(keypressSlider, {
	start: 40,
	step: 10,
	range: {
		'min': 0,
		'20%': [ 300, 100 ],
		'50%': [ 800, 50 ],
		'max': 1000
	}
});

keypressSlider.noUiSlider.on('update', function( values, handle ) {
	input.value = values[handle];
});

input.addEventListener('change', function(){
	keypressSlider.noUiSlider.set([null, this.value]);
});
Listen to keypress on the input
// Listen to keydown events on the input field.
input.addEventListener('keydown', function( e ) {

	// Convert the string to a number.
	var value = Number( keypressSlider.noUiSlider.get() ),
		sliderStep = keypressSlider.noUiSlider.steps()

	// Select the stepping for the first handle.
	sliderStep = sliderStep[0];

	// 13 is enter,
	// 38 is key up,
	// 40 is key down.
	switch ( e.which ) {
		case 13:
			keypressSlider.noUiSlider.set(this.value);
			break;
		case 38:
			keypressSlider.noUiSlider.set( value + sliderStep[1] );
			break;
		case 40:
			keypressSlider.noUiSlider.set( value - sliderStep[0] );
			break;
	}
});
§

Skipping steps

When using a stepped slider, your configuration may require that certain steps aren't available. Using the snap feature, this effect can be created.

Notice how 40 and 80 can't be selected on the slider.

Initialize a snapping slider
var skipSlider = document.getElementById('skipstep');

noUiSlider.create(skipSlider, {
    range: {
        'min': 0,
        '10%': 10,
        '20%': 20,
        '30%': 30,
		// Nope, 40 is no fun.
        '50%': 50,
        '60%': 60,
        '70%': 70,
		// I never liked 80.
        '90%': 90,
        'max': 100
    },
    snap: true,
    start: [20, 90]
});
Read the slider values
var skipValues = [
	document.getElementById('skip-value-lower'),
	document.getElementById('skip-value-upper')
];

skipSlider.noUiSlider.on('update', function( values, handle ) {
	skipValues[handle].innerHTML = values[handle];
});
§

Using the slider with huge numbers

If you are working with arbitrarily large numbers, you should not use these directly in noUiSlider, as you'll run into some JavaScript limitations. Instead, you should map your values to an array.

Numbers is JavaScript are Double Precision Floats, which can store numbers up to 2^53 (9007199254740992) precisely. For reference, see this StackOverflow question, or issue #427 filed on GitHub.

As an example, see the 'range' option for a RAM selector offering 14 steps from 512MB to 8GB. The 'step' are ommited for clarity. The values are provided as bytes. A better solution would be to abstract the byte values away from the slider, looking up the byte values in an array. This keeps the slider configuration simple and prevents issues with floating point precision.

(These values fit within the limit just fine, but demonstrate the point really well!)

range: {
	  'min': 0,
	 '7.6%': 2097152,
	'15.3%': 4194304,
	'23.0%': 8388608,
	'30.7%': 16777216,
	'38.4%': 33554432,
	'46.1%': 67108864,
	'53.8%': 134217728,
	'61.5%': 268435456,
	'69.2%': 536870912,
	'76.9%': 1073741824,
	'84.6%': 2147483648,
	'92.3%': 4294967296,
	  'max': 8589934592
}
Setup
var bigValueSlider = document.getElementById('slider-huge'),
	bigValueSpan = document.getElementById('huge-value');

noUiSlider.create(bigValueSlider, {
	start: 0,
	step: 1,
	format: wNumb({
		decimals: 0
	}),
	range: {
		min: 0,
		max: 13
	}
});
// Note how these are 'string' values, not numbers.
var range = [
	'0','2097152','4194304',
	'8388608','16777216','33554432',
	'67108864','134217728','268435456',
	'536870912','1073741824',
	'2147483648','4294967296',
	'8589934592'
];

bigValueSlider.noUiSlider.on('update', function ( values, handle ) {
	bigValueSpan.innerHTML = range[values[handle]];
});
§

Adding keyboard support

Much like the keypress example, handles can be made keyboard-focusable.

Initializing the slider
var slider = document.getElementById('keyboard');

noUiSlider.create(slider, {
	start: 10,
	step: 10,
	range: {
		'min': 0,
		'max': 100
	}
});
Listen to keypress on the handle
var handle = slider.querySelector('.noUi-handle');

handle.setAttribute('tabindex', 0);

handle.addEventListener('click', function(){
	this.focus();
});

handle.addEventListener('keydown', function( e ) {

	var value = Number( slider.noUiSlider.get() );

	switch ( e.which ) {
		case 37: slider.noUiSlider.set( value - 10 );
			break;
		case 39: slider.noUiSlider.set( value + 10 );
			break;
	}
});
CSS
.noUi-handle:focus {
	box-shadow: 0 0 5px orange;
}
§

Working with dates

As all dates in JavaScript can be represented as time, noUiSlider can handle them, too. This example will show you how to convert dates to numerical ranges, and then use the update event to display them in a pretty format.

We'll be creating timestamps from strings. In order to do this easily, we'll define a new helper function. This function accepts a string, creates a new Date and then returns it as a timestamp.

In in overview below you'll find the code used to run this example. For readability, all helper functions have been moved into their own tab.

Timestamps
// Create a new date from a string, return as a timestamp.
function timestamp(str){
    return new Date(str).getTime();   
}
Setup
var dateSlider = document.getElementById('slider-date');

noUiSlider.create(dateSlider, {
// Create two timestamps to define a range.
    range: {
        min: timestamp('2010'),
        max: timestamp('2016')
    },

// Steps of one week
    step: 7 * 24 * 60 * 60 * 1000,

// Two more timestamps indicate the handle starting positions.
    start: [ timestamp('2011'), timestamp('2015') ],

// No decimals
	format: wNumb({
		decimals: 0
	})
});
Slider control
var dateValues = [
	document.getElementById('event-start'),
	document.getElementById('event-end')
];

dateSlider.noUiSlider.on('update', function( values, handle ) {
	dateValues[handle].innerHTML = formatDate(new Date(+values[handle]));
});
Helper functions and formatting

The nth function was borrowed from this StackOverflow question.

// Create a list of day and monthnames.
var
	weekdays = [
		"Sunday", "Monday", "Tuesday",
		"Wednesday", "Thursday", "Friday",
		"Saturday"
	],
	months = [
		"January", "February", "March",
		"April", "May", "June", "July",
		"August", "September", "October",
		"November", "December"
	];

// Append a suffix to dates.
// Example: 23 => 23rd, 1 => 1st.
function nth (d) {
  if(d>3 && d<21) return 'th';
  switch (d % 10) {
        case 1:  return "st";
        case 2:  return "nd";
        case 3:  return "rd";
        default: return "th";
    }
}

// Create a string representation of the date.
function formatDate ( date ) {
    return weekdays[date.getDay()] + ", " +
        date.getDate() + nth(date.getDate()) + " " +
        months[date.getMonth()] + " " +
        date.getFullYear();
}
§

Creating a toggle

Many application interfaces have options that can be turned on or off using switches. noUiSlider is well suited for this, especially because of the wide touch support.

The update event can be used to keep track of changes to the handle. We'll set the range to [0, 1], which leaves one step of 1.

Toggle
var toggleSlider = document.getElementById('slider-toggle');

noUiSlider.create(toggleSlider, {
	orientation: "vertical",
	start: 0,
	range: {
		'min': [0, 1],
		'max': 1
	},
	format: wNumb({
		decimals: 0
	})
})

toggleSlider.noUiSlider.on('update', function( values, handle ){
	if ( values[handle] === '1' ) {
		toggleSlider.className += ' off';
	} else {
		toggleSlider.className = toggleSlider.className.slice(0, -4);
	}
});
CSS
#slider-toggle {
	height: 50px;
}
#slider-toggle.off .noUi-handle {
	border-color: red;
}
§

Soft limits

If you want to disable the edges of a slider, the set event can be used to reset the value if a limit is passed. Note how the handle 'bounces back' when it is released below 20 or above 80. noUiSlider doesn't support disabling edges altogether, but this effect might be created visually by setting padding on the slider.

Setting up the slider
var softSlider = document.getElementById('soft');

noUiSlider.create(softSlider, {
	start: 50,
	range: {
		min: 0,
		max: 100
	},
	pips: {
		mode: 'values',
		values: [20, 80],
		density: 4
	}
});
Resetting using the set event
softSlider.noUiSlider.on('change', function ( values, handle ) {
	if ( values[handle] < 20 ) {
		softSlider.noUiSlider.set(20);
	} else if ( values[handle] > 80 ) {
		softSlider.noUiSlider.set(80);
	}
});