I need to create a scientific input slider. More precisely:
- n ticks, example: no matter the range (0 – 200, 1 – 11, etc.), I want 11 ticks covering the whole range
- the number value label below each tick
- no "glue" attraction effect when the slider cursor is near a tick
Mockup:
Note:
-
this is not a duplicate of Ticks for type="range" HTML input because of these 3 points.
-
browser support: at least Chrome
The following code produces a HTML slider with ticks, and it works. However, it fails both the 2nd and 3rd criteria above.
input { width: 400px; }
<input type=range min=0 max=200 value=0 step=1 list=tickmarks>
<datalist id=tickmarks>
<option>0</option>
<option>20</option>
<option>40</option>
<option>60</option>
<option>80</option>
<option>100</option>
<option>120</option>
<option>140</option>
<option>160</option>
<option>180</option>
<option>200</option>
</datalist>
Is there an attribute for an HTML <input type="range">
to enable these "number-labelled" ticks?
Is an implementation that satisfies all three criteria possible?
6
Answers
You can achieve this by putting a div below your range that you divide into sections. The code below is just a proof-of-concept, which already works, but when you actually integrate it into your project, you will need to make it reusable and adjustable.
As Lajos Arpad’s answer indicates, it’s best to avoid using
datalist
as your requirements go beyond what it’s capable of. You’ll need to manually create the ticks with number values.The following code uses a HTML layout similar to the original code in your question, with styling to suit. Note that the width is set on a parent element, and if the parent is too small then the tick numbers will wrap to a new line. To counter this you may need to decrease the tick number font size.
To get the ticks lining up properly across all major browsers it is perhaps better to style the slider so it looks identical across browsers. Styles targeting Chrome- and Firefox-specific pseudo-elements for range sliders are included. The result should look the same across all Chromium and Mozilla based browsers.
Note that a truly cross-browser method of filling in the range slider, as shown in the question, can only be achieved with JavaScript. The JavaScript here is basically copied from this answer
You can use a
datalist
with a list ofoption
, but it will require you to addlabel
texts as thevalue
will not be used as tickmark values.generic setup (MDN: input type="range", Adding tick marks)
For the labels you have two options:
option 1: use
label
with textoption 2: use an option text
When using both a
label
text and option text, the latter will be ignored. For the snippet I used option 1.tickmarks
input type="range"
anddatalist
must have equalwidth
. In the snippet I used CSS custom property--slider-width: 100%
to set the width of either element.datalist
as Flexbox row container withjustify-content: space-between
is perfectly suited to distribute the tickmark labels. It pushes the outer labels to their respective parent left and right margins, while evenly distributing the rest of the labels over the remaining space.width
equal to the largest text. In the snippet I took the width of label200
.text-align: center
.Depending on label texts used some fiddling with
margin/padding
ofoption:first-child
and/oroption:last-child
might be required.Bonus in the snippet I added class
.vertical
to show how you can useflex-direction: column
andwriting-mode: vertical-lr
to easily get 90 degree rotated tickmark labels.UPDATE
As initially commented the above method does not solve the ‘glue’ effect caused by the
datalist
tickmarks in Firefox browsers. Additionally, Firefox opens anoption
select list upon second click at a tickmark, treating adatalist
as aselect
. While Firefox specific behavior and probably known/preferred by users, it may be unwanted for a site.However, after investigation, it appears the forementioned behavior is very hard, if not impossible, to disable. One could opt to create a fully custom range slider with Javascript, but that may prove to be overkill: create a workaround for a single browser, disabling behavior that may or may not be changed in the future.
Tried methods that fail:
datalist,option { pointer-events: none }
<option disabled />
works, but removes tickmark<datalist type="range" autocomplete="off">
<input type="range" autocomplete="off">
<option autocomplete="off">
<option label=".."/>
withoutvalue=".."
<option value="..">..</option>
text instead oflabel
<input type="range">
in a<form>
with all elementsautocomplete="off"
One possible solution is to dynamically create a scale. There are many details to consider, such as steps. You can start here:
According to me and as everyone suggested in this answer It is recommended to not use
datalist
if your needs exceed its capabilities. Instead, you should manually create the ticks with numerical values.I have created another solution for this one with web component, with it you have far more control and customization.