After reading this I was wondering if it is possible to show ticks in Chrome and Firefox for a type="range"
number input? The closest thing I could find on this subject is this.

- 1,226
- 2
- 13
- 26
-
1@chsdk that site does not show how to generate tick marks, unfortunately – tadasajon Mar 16 '16 at 22:38
-
1I've written a CSS-only component for this https://codepen.io/vsync/pen/mdEJMLv – vsync Jan 18 '22 at 12:57
6 Answers
Input ranges are still a bit of a nightmarish hack when it comes to styling. That said, displaying tickmarks on major browsers is possible, with a bit of elbow grease and browser-specific solutions.
Internet Explorer / Edge
As you seem to be aware, Internet Explorer will show ticks by default if you add the HTML step
attribute. In a weird twist of events, Internet Explorer and Edge are arguably the most flexible browser when it comes to styling input ranges.
<input type="range" min="0" max="100" step="25">
Chrome / Safari
In Chrome and other Webkit browsers (including Safari), you can use the datalist element to provide a custom set of tick locations on the slider. While all major browsers support this element, Firefox (and other Gecko browsers) won't show visible tick marks.
<input type="range" min="0" max="100" step="25" list="steplist">
<datalist id="steplist">
<option>0</option>
<option>25</option>
<option>50</option>
<option>75</option>
<option>100</option>
</datalist>
Firefox
In Firefox and other Gecko-based browsers, we'll need to use some vendor-specific CSS to add the tick marks. You'll have to customize this to whatever looks the most natural to you. In this example, I've used a horizontal repeating gradient to add "vertical stripes" that look like tick marks, but you could also use a background image, or any other style you want. You could even use a bit of Javascript to load information from the datalist element, then generate an appropriate gradient and apply it to the element so that it all happens automatically, and so it can support custom arbitrary stops.
input[type="range"]::-moz-range-track {
padding: 0 10px;
background: repeating-linear-gradient(to right,
#ccc,
#ccc 10%,
#000 10%,
#000 11%,
#ccc 11%,
#ccc 20%);
}
<input type="range" min="0" max="100" step="25" list="steplist">
<datalist id="steplist">
<option>0</option>
<option>25</option>
<option>50</option>
<option>75</option>
<option>100</option>
</datalist>
Compatibility notes: As pointed out in the comments, datalist is not supported by some browsers. Depending on how those browsers handle unsupported / unrecognized elements, this may result in the browsers displaying the option values as plain text below your range input. If targeting the widest possible range of browsers is important to you, this may be a problem.
One solution is to use the awkward repeating-linear-gradient
kludge for webkit browsers in addition to gecko browsers, and then remove the datalist entirely.
Another solution would be to use CSS to explicitly set the datalist to display: none
. This solution is probably the most preferable, as you aren't compromising features to provide legacy support.

- 8,477
- 3
- 48
- 86
-
[Keep in mind potential compatibility issues](http://caniuse.com/#feat=datalist). – charles Oct 28 '14 at 16:55
-
@charles since it's not a visible element, it will simply be ignored by browsers that don't support it, right? – Woodrow Barlow Oct 28 '14 at 17:53
-
Depends completely on how the browser handles unrecognized tags. A compatibility issue could definitely be the datalist options being visible. I haven't tested this though. – charles Oct 29 '14 at 12:09
-
1@charles that's true, thank you. i suppose if datalist compatibility is a concern, the best approach would be to use the (frustratingly hacky) `repeating-linear-gradient` solution for both webkit and gecko browsers. – Woodrow Barlow Oct 29 '14 at 13:48
-
-
Does anyone have an example of how one would use `repeating-linear-gradient` to generate custom tick-marks? I'm guessing you would use a `::before` pseudo element and apply the gradient to it, but is there a different approach? – rojobuffalo Feb 06 '15 at 16:55
-
@JonCrowell can you tell me which browsers it fails on and how? i'll update the answer. – Woodrow Barlow Oct 02 '15 at 13:31
-
7i'm a little sad that this answer is still relevant almost three years later. – Woodrow Barlow Sep 01 '17 at 15:08
-
Ion.RangeSlider from JS (What Shiny uses) is cross browser compatible. http://ionden.com/a/plugins/ion.rangeSlider/start.html – Brian Wiley Dec 30 '20 at 03:28
Range input with CSS-only ticks
I have developed my own lightweight component which renders ticks using only CSS, with linear-gradient
background
property, by using CSS variables (AKA "custom properties").
Unfortunately, a wrapper element is needed, but it's the most minimal HTML modifications I came up with which allows the outcome.
Manual-syncing between the range input's attributes and the wrapper element's style
attribute which hosts the variables is also unfortunately needed.
Fancy Codepen Demo
body {
height: 100vh;
display: grid;
place-items: center;
}
.range {
--ticksThickness: 2px;
--ticksHeight: 30%;
--ticksColor: silver;
display: inline-block;
background: silver;
background: linear-gradient(to right, var(--ticksColor) var(--ticksThickness), transparent 1px) repeat-x;
background-size: calc(100%/((var(--max) - var(--min)) / var(--step)) - .1%) var(--ticksHeight);
background-position: 0 bottom;
position: relative;
}
/* min / max labels at the edges */
.range::before, .range::after {
font: 12px monospace;
content: counter(x);
position: absolute;
bottom: -2ch;
}
.range::before {
counter-reset: x var(--min);
transform: translateX(-50%);
}
.range::after {
counter-reset: x var(--max);
right: 0;
transform: translateX(50%);
}
.range > input {
width: 300px;
margin: 0 -6px; /* Critical adjustment */
}
<div class="range" style="--step:10; --min:20; --max:100">
<input type="range" min="20" max="100" step="10" value="30">
</div>

- 118,978
- 58
- 307
- 400
I hope, this will help somebody formating the tick and datalist under FF. Requires the options to be evenly spaced and input + datalist have to have the same width.
input[type="range"] {
width: 100%;
margin: 0;
box-sizing: border-box;
}
datalist {
display: flex;
width: 100%;
justify-content: space-between;
margin-top: -23px;
padding-top: 0px;
}
option {
width: 2ex;
display: flex;
justify-content: center;
height: 42px;
align-items: end;
background-image: url(tick.png);
height: 4ex;
background-position-y: -15px;
background-position-x: center;
z-index: -1;
}

- 91
- 1
- 1
-
1This is a good solution. To support Safari, I used div instead of datalist and spans instead of options. Note, Bootstrap 4 provides convenient flex classes. – Y. E. Nov 25 '18 at 10:33
Introduction
Inspired by user10452457's answer I created an approach that corrects the spacing of datalist elements especially when the length of datalist entries varies. The downside is that you have to specify the length of the datalist in its style
attribute: <datalist style="--list-length: XYZ;">...</datalist>
. If the length is not known when creating the datalist you can change this value by using some javascript.
This approach works by splitting the width of the range input in such a way that the text of the datalist entry is centered below the range thumb. The first/last datalist entry is aligned to the left/right. This method requires the width
of the range input to be 100%
and the margin-left
to be 0
.
Default range and thumb
The following css styles a datalist that directly follows a range input when using the default thumb of Firefox that has a width of 12px
.
/* style range */
input[type=range] {
width: 100%;
max-width: 100%;
margin-left: 0;
}
/* style datalist */
input[type=range] + datalist {
display: flex;
margin-top: -4px;
}
input[type=range] + datalist option {
display: inline-block;
width: calc((100% - 12px) / (var(--list-length) - 1));
text-align: center;
}
input[type=range] + datalist option:first-child {
width: calc((100% - 12px) / ((var(--list-length) - 1) * 2) + 6px);
text-align: left;
}
input[type=range] + datalist option:last-child {
width: calc((100% - 12px) / ((var(--list-length) - 1) * 2) + 6px);
text-align: right;
}
<input type="range" min="1" max="9" id="my-range" list="my-datalist"/>
<datalist id="my-datalist" style="--list-length: 9;"><!--
---><option>1</option><!--
---><option>2</option><!--
---><option>3</option><!--
---><option>A</option><!--
---><option>B</option><!--
---><option>C</option><!--
---><option>Four</option><!--
---><option>Five</option><!--
---><option>Six</option><!--
---></datalist>
Custom range and thumb
When you want to use a custom style for your range input you can use the following style. The --thumb-width
variable holds the with of the thumb and is used for the correct calculation.
// change thumb-width variable on input change
var tw = document.getElementById('thumb-width');
var mr = document.getElementById('my-range');
var ml = document.getElementById('my-datalist');
tw.onchange = () => {
mr.style.setProperty('--thumb-width', tw.value + 'px');
ml.style.setProperty('--thumb-width', tw.value + 'px');
}
/* set thumb width */
input[type=range], input[type=range] + datalist { --thumb-width: 8px; }
/* style range */
input[type=range] {
-webkit-appearance: none; /* hide track and thumb */
width: 100%;
max-width: 100%;
margin-left: 0;
}
/* style datalist */
input[type=range] + datalist {
display: flex;
margin-top: -4px;
}
input[type=range] + datalist option {
display: inline-block;
width: calc((100% - var(--thumb-width)) / (var(--list-length) - 1));
text-align: center;
}
input[type=range] + datalist option:first-child {
width: calc((100% - var(--thumb-width)) / ((var(--list-length) - 1) * 2) + var(--thumb-width) / 2);
text-align: left;
}
input[type=range] + datalist option:last-child {
width: calc((100% - var(--thumb-width)) / ((var(--list-length) - 1) * 2) + var(--thumb-width) / 2);
text-align: right;
}
/* style Firefox range and thumb */
input[type=range]::-moz-range-track {
background: #eee;
cursor: pointer;
height: 2px;
border: 1px solid #888;
border-radius: 1px;
}
input[type=range]::-moz-range-thumb {
background: #eee;
box-sizing: border-box;
width: var(--thumb-width);
height: 20px;
cursor: pointer;
border: 1px solid #888;
border-radius: 3px;
}
/* style Chrome range and thumb */
input[type=range]::-webkit-slider-runnable-track {
background: #eee;
cursor: pointer;
height: 2px;
border: 1px solid #888;
border-radius: 1px;
}
input[type=range]::-webkit-slider-thumb {
background: #eee;
box-sizing: border-box;
width: var(--thumb-width);
height: 20px;
cursor: pointer;
border: 1px solid #888;
}
<label>Thumb width:</label>
<input type="number" id="thumb-width" min="4" max="60" step="4" value="10"/>
<br><br>
<input type="range" min="1" max="9" id="my-range" list="my-datalist"/>
<datalist id="my-datalist" style="--list-length: 9;"><!--
---><option>1</option><!--
---><option>2</option><!--
---><option>3</option><!--
---><option>A</option><!--
---><option>B</option><!--
---><option>C</option><!--
---><option>Four</option><!--
---><option>Five</option><!--
---><option>Six</option><!--
---></datalist>
Version History
- v1.1 - as suggested by @Lien, changed the datalist style from
display: block
toflex

- 317
- 1
- 4
- 6
-
1This is the only one that correctly displays labels & ticks on the whole page, in both firefox & chrome. – Steve Horvath Feb 11 '21 at 02:10
-
It doesn't display the labels in the right place in Chrome for me. They're wrapped. – Timmmm Mar 10 '22 at 14:37
-
1
You can use the <datalist>
with the range:
<input type="range" min="0" value="0" max="10" step="1" list="ticks">
<datalist id="ticks">
<option>0</option>
<option>2</option>
<option>4</option>
<option>6</option>
<option>8</option>
<option>10</option>
</datalist>

- 204,283
- 31
- 260
- 272
-
@WoodrowBarlow - According to MDN, range has FF support since v23 and datalist since v4. – j08691 Oct 28 '14 at 16:06
-
the tick marks aren't visible, though. it does support them in that it "locks" into those positions on the slider, but the marks aren't displayed. – Woodrow Barlow Oct 28 '14 at 16:08
-
-
2how did this answer get 3 upvotes even though the ticks are not visible? – tadasajon Sep 30 '15 at 13:43
-
@JonCrowell - Because the question asked for a Chrome and Firefox solution, and while FF has yet to implement the tick marks, it works in both. – j08691 Sep 30 '15 at 13:56
-
@j08691 well, I'm using Chrome and when I click on "Run Code Snippet" above I don't see tick marks. – tadasajon Sep 30 '15 at 14:47
-
@JonCrowell - The ticks appear in the latest Chrome on Windows and Linux. As well as Opera. – j08691 Sep 30 '15 at 15:32
-
if the ticks are to be shown, you'll want a way to style them as well, which I still have not found yet – jsaddwater May 16 '17 at 08:21
If custom tick marks are required, pair a slider with a flexbox of custom values. Line up the width of the slider to match the offset of the terminal ticks.
Note: This example only demonstrates the static visuals. JavaScript will be required to translate the slider percentage to custom values, and to highlight the selected tick.
:root {
font-family: system-ui, -apple-system, -apple-system-font, 'Segoe UI', 'Roboto', sans-serif;
}
h1 {
font-size: 1.1em;
text-transform: uppercase;
color: darkgray;
letter-spacing: .2em;
}
.options {
width: 30em;
border: 1px solid silver;
border-radius: 1em;
background-color: ghostwhite;
padding: 0 0 1em 0;
text-align: center;
display: flex;
flex-direction: column;
}
.ticks {
display: flex;
}
.o_txt {
flex: 1;
}
.slider {
width: 87%; /* manually adjust this to look right */
margin: auto;
cursor: grab;
}
.o_on {
font-weight: 500;
color: blue;
}
<div class="options">
<h1>Budget</h1>
<input class="slider" type="range" min="0" max="100" step="10" list="steplist" value="40" />
<datalist id="steplist">
<option>0</option>
<option>10</option>
<option>20</option>
<option>30</option>
<option>40</option>
<option>50</option>
<option>60</option>
<option>70</option>
<option>80</option>
<option>90</option>
<option>100</option>
</datalist>
<div class="ticks">
<span class="o_txt">$100</span>
<span class="o_txt">$1K</span>
<span class="o_txt o_on">$10K</span>
<span class="o_txt">$100K</span>
<span class="o_txt">$1M</span>
<span class="o_txt">$10M</span>
</div>
</div>

- 2,041
- 25
- 19