M&M JS Range (M&M JSR) is library for JavaScript. It provides You with excellent solution for creating so-called range-inputs. Range input is form's field where one can choose a value from min-max range. Although HTML 5 comes with input[type="range"]
its functionality lacks a lot of features. M&M JSR gives You anything You may need.
Homepage: https://mm-jsr.github.io/
Newest version: 1.0.0 (17.9KB without gzipping)
Tested browser support: Firefox (57+), Chrome (63+), Edge (41+)
- Mort&Mortis JS Range (M&M JSR)
- resolution responsivity, due to use of percentage values,
- custom minimum and maximum values (including negative numbers),
- custom step of values (literally custom, it can be 0.001, 2 or 100),
- any number of sliders,
- collapsing labels,
- fully and easily customizable through CSS and configuration,
- formatter for labels,
- support for touch devices,
- support for keyboard,
- support for screen-readers (not implemented yet).
- lightweight,
- customizable,
- disabled people wise (not implemented yet),
- no dependencies (pure JavaScript),
- multiple instances and zero conflicts,
- sends value to inputs, so they can be easily send via form,
- free.
-
Clone the repository:
git clone https://github.com/mm-jsr/jsr.git
Or download it manually through GitHub site.
-
Include in your code:
In HTML
<head>
section:<link rel="stylesheet" href="[path_to_jsr_directory]/dist/assets/css/mm-jsr.css">
And in HTML scripts section (in example in the end of body:)
<script src="[path_to_jsr_directory]/dist/main.js"></script>
-
Install via npm:
npm install mm-jsr
-
Include in your JS code:
import JSR from 'mm-jsr';
or, depending on your module system:
const JSR = require('mm-jsr')
;Since JSR is packed as UMD bundle, You can include also directly as JSR:
import 'mm-jsr';
-
Add CSS:
In your
<head>
section:<link rel="stylesheet" href="node_modules/mm-jsr/dist/assets/css/main.css">
or to the imports section of your css file (considering your bundling tool resolves your
node_modules
folder):@import 'mm-jsr/dist/assets/css/main.css'
or (in your JS code) if your bundling tool resolves
node_modules
and allows to load all assets from JS (Webpack does):import 'mm-jsr/dist/assets/css/main.scss'
For simple implementation see dist/index.html in repository.
The example below will create range with 3 sliders of values: 25, 50, 75 from 0-100 range (which is default).
-
Create HTML:
- HTML must be builded of n-inputs, where
n
is the number of sliders You want to use. - Each input should have it's unique
[id]
(though it's not necessary). - Input's validation rules (that includes
[min|max]
attributes if[type="range"]
) must allow numbers from range min-max (which is 0-100 by default, other if set via configuration) with optional decimals.
<input id="jsr-1-1" name="range1" type="range" min="0" max="100" step="1" value="25"> <input id="jsr-1-2" name="range2" type="range" min="0" max="100" step="1" value="50"> <input id="jsr-1-3" name="range3" type="text" value="75">
- HTML must be builded of n-inputs, where
-
Create instance of JSR on inputs, and set it's starting values, and number of sliders You want to use:
- Inputs must be provided as CSS selector rule, as string (if one slider) or as array of strings (if one or more sliders) or must be provided as DOM objects or array of DOM objects.
- Number of sliders must match the number of inputs.
- Number of values must match the number of sliders.
- Values should match min-max range.
new JSR(['#jsr-1-1', '#jsr-1-2', '#jsr-1-3'], { sliders: 3, values: [25, 50, 75] });
Options object with defaults looks like follows:
{
min: 0, // Minimal value
max: 100, // Maximum value
step: 1, // Step of values. It can be any value (10, 1, 0.1, 0.01 and so on)
values: [25, 75], // Values from smallest to biggest
labels: { // Configuration for labels
minMax: true, // Boolean if minimum and maximum labels should be displayed (applies CSS display: none;)
formatter: null
},
limit: {
show: false // Determines, if the limit should be visible on bar or not.
},
grid: {
color: 'rgba(0, 0, 0, 0.3)', // Color of bars and text of grid. Can by any CSS color.
height: 10, // Height of bars of grid.
fontSize: 10, // Font size of text (in pixels).
fontFamily: 'sans-serif', // Font family of text (any CSS font-family value).
textPadding: 5 // Vertical distance between text and bars (in pixels).
}
log: 'error' // available values: 'debug', 'info', 'warn', 'error'
}
Custom options should go together with sliders
and values
options in JSR constructor (see example).
JSR supports keyboard control. First of all one of sliders needs to be focused (by TAB or by click).
- By clicking
left/right arrow
the value is changed byoptions.step
. - If the
CTRL
is pressed along with arrow, the value is changed byoptions.step x10
. - If the
SHIFT
is pressed along with arrow, the value is changed byrange x5%
(by the 5% of whole range).
NOTE: In case of SHIFT
and CTRL
keys pressed simultaneously, SHIFT
takes priority.
Most of the API methods return this
, so methods can be chained one by one.
Values of sliders can be set programmatically via JS:
const range = new JSR(['#jsr-1-1', '#jsr-1-2', '#jsr-1-3'], {
sliders: 3,
values: [25, 50, 75]
});
// Later in code:
range.setValue(0, 40); // where 0 is the 0-index number of slider, and 40 is the value
You can listen on certain events, by executing .addEventListener(event, callback)
method on JSR instance.
const range = new JSR(['#jsr-1-1', '#jsr-1-2', '#jsr-1-3'], {
sliders: 3,
values: [25, 50, 75]
});
range.addEventListener('update', (input, value) => {
console.log(input, value);
});
Available event names and their callback arguments:
update
-([NodeElement] input, [Integer/Float] value)
- called by InputUpdate module after updating input's value.
At any time methods .enable()
and .disable()
can be called to enable/disable slider.
Slider, while disabled, will have .jsr--disabled
class.
It is possible to programmaticaly change minimum and maximum values the sliders can achieve. It is called limit.
It can be done via config or .setLimit(limit, value)
API option.
new JSR('...', {
...
limit: {
show: [boolean], // Defaults to false. Limit works even if `show` is false!
min: [value],
max: [value]
}
...
});
jsr.setLimit('min', 25).setLimit('max', 70);
Limit cannot be set to value bigger than min/max.
BEWARE: setting new limit (via API) refreshes all values to ensure noone exceeds the limit. This cause n refresh events to be called.
If you change the show
property after initializing JSR, some limit need to be set to update visibility state.
To disable limit set it to null
.
JSR relies on CSS as much as possible. JSR CSS selectors are written in BEM methodology, which means, that the specificity is as flat as possible. You should have no problems with overwriting styles.
Everything (sliders, labels, bars) work in % positions, which means that the position of elements should be window size-independent.
See default styles in style file.
Since slider is bigger than the dot itself to make targetting easier, the dot is painted on ::before
pseudoelement.
When moving slider by mouse (or finger) slider receives .jsr_slider--active
class which indicates, that this slider is moving. It is removed after releasing mouse button (finger). It is not styled by default. It doesn't work if bars are dragged.
Every slider can be focused by keyboard or by clicking. Style with .jsr_slider:focus
.
Because merging labels is created through inserting on DOM level following label into preceding label, the merged label can be accessed by .jsr_label .jsr_label
selector. By default this style removes padding, fixes font-size, and such things.
The labels are separated by pseudo-element .jsr_label .jsr_label::before
. It's content
property is the separator. By default it is: content: ' - ';
.
Touch event on mobile devices is supported by JSR. Because moving the finger around the screen to move slider caused the view to go up and down, I decided to lock the screen on touch start. This means, that to document root .jsr_lockscreen
class is applied, which sets the size of document root to window size. If it causes any problems, You can set overflow: visible; width: auto; height: auto;
on .jsr_lockscreen
class, and report the issue through GitHub's issue system.
Issue: it may cause screen jump on mobile screens, because after locking screen the top address bar may disappear.
https://mm-jsr.github.io/#demo
A grid displays vertical bars, by default beneath the bar, which help to target values on bar. The grid is clickable, just like bar.
Some of the range solutions use multiple divs to draw bars. JSR uses canvas, because it's far faster solution, and it doesn't pollute DOM.
Since the canvas has JS-only side, bars' color can be set only via JS by grid.color
option. It tolerates any CSS color values. If you want to have grid displayed and text hidden, just set text color to rgba(0, 0, 0, 0)
(transparent).
Grid uses config.labels.formatter
to format text.
By default labels shows the actual value of input, but the config.labels.formatter
can be set to any function, which returned value will be displayed to the user as label. The function is provided with a current slider value as first argument.
This is an example of JSR configuration which enables to choose between dates (DD-MM-YYYY) 01-01-2017 and 30-12-2017:
new JSR(['#range-7-1'], {
sliders: 1, // Only one date
values: [1], // Whatever, will be set to minimum anyway, can be current date timestamp
min: 1483228801000, // timestamp of minimum value (01-01-2017)
max: 1514678399000, // timestamp of maximum value (30-12-2017)
step: 1000 * 60 * 60 * 24, // full day (mili * seconds * minutes * hours)
labels: {
formatter: function (value) {
const date = new Date(value); // Get date from value
const day = date.getUTCDate(); // Get day
const month = date.getMonth() + 1; // Get month
const year = date.getUTCFullYear(); // Get year
return `${day}-${month}-${year}`; // Display
}
}
});
Some of the modules can be safely disabled:
labels
htmlLabels
touchSupport
inputUpdater
grid
by setting modules[moduleName]
to false in JSR configuration.
HTML Label support module enables support for focusing sliders by clicking on appropriate label.
Since <label>
is connected with its input by [for]
attribute, it's necessary to connect it properly. Clicking on label focuses connected input (slider).