You can use a datalist
with a list of option
, but it will require you to add label
texts as the value
will not be used as tickmark values.
generic setup (MDN: input type="range", Adding tick marks)
<input type="range" list="tickmark-list">
<datalist id="tickmark-list">
<option value=1 label="1"/>
<option value=N label="N"/>
</datalist>
For the labels you have two options:
option 1: use label
with text
<option value="1" label="tickmark-value-1"/>
<option value="N" label="tickmark-value-N"/>
option 2: use an option text
<option value="1">tickmark-value-1</option>
<option value="N">tickmark-value-N</option>
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"
and datalist
must have equal width
. In the snippet I used CSS custom property --slider-width: 100%
to set the width of either element.
datalist
as Flexbox row container with justify-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.
- For even distribution of tickmark texts it is best to give them all a
width
equal to the largest text. In the snippet I took the width of label 200
.
- To center the label text below the tickmarks use
text-align: center
.
- The tickmarks are default inserted by the range slider itself and does not require any extra code.
Depending on label texts used some fiddling with margin/padding
of option:first-child
and/or option:last-child
might be required.
Bonus in the snippet I added class .vertical
to show how you can use flex-direction: column
and writing-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 an option
select list upon second click at a tickmark, treating a datalist
as a select
. 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=".."/>
without value=".."
<option value="..">..</option>
text instead of label
- embed
<input type="range">
in a <form>
with all elements autocomplete="off"
- Disable autocomplete history in browser Privacy Settings
:root { --slider-width: 100% }
input, datalist {
width: var(--slider-width);
}
datalist {
display: flex;
flex-direction: row;
justify-content: space-between;
}
option {
text-align: center;
width: 1.78rem; /* ~width of label '200' */
}
.vertical {
flex-direction: column;
writing-mode: vertical-lr;
}
input[list="tickmarks2"] { margin: 0 }
.vertical option { text-align: right; width: 1.5rem }
<div id="SO75802357">
<input type=range min=0 max=200 value=0 step=1 list="tickmarks1">
<datalist id="tickmarks1">
<option value=0 label="0" />
<option value=20 label="20" />
<option value=40 label="40" />
<option value=60 label="60" />
<option value=80 label="80" />
<option value=100 label="100"/>
<option value=120 label="120"/>
<option value=140 label="140"/>
<option value=160 label="160"/>
<option value=180 label="180"/>
<option value=200 label="200"/>
</datalist>
<br><br>
<input type=range min=0 max=200 value=0 step=1 list="tickmarks2">
<datalist id="tickmarks2" class="vertical">
<option value=0 label="0" />
<option value=20 label="20" />
<option value=40 label="40" />
<option value=60 label="60" />
<option value=80 label="80" />
<option value=100 label="100"/>
<option value=120 label="120"/>
<option value=140 label="140"/>
<option value=160 label="160"/>
<option value=180 label="180"/>
<option value=200 label="200"/>
</datalist>
</div>