
We need to talk about multi-handle range sliders… Really, we do. They’re one of those UI elements we see on a variety of web shops indicating price ranges; we see them for selecting time-slots; we see them for filtering between a variety of lenght units. Creating these experiences is more often inaccessible than just working, and even when I found the so-called perfect library, I’d still run into limitations for styling and expanding upon it. I thought that I should do something about this. I might be way over my head, and that is why I need your help...
The proposal: <rangegroup>
In this article, I’m going to summarize the current explainer. I want you to know that this is very early stage, which is exactly why it needs noise from other developers. For those who want to take a deep dive, these are the steps you can take:
- Read the full explainer
- Look at the prototype (using a web component)
- filling out the feedback form
Note that if you have already given me feedback, I am still in the process of collecting more of it 🙂 I haven’t forgotten, and I value each bit of feedback a lot.
So now, let me summarize. What if we could combine two <input type="range" />
and each of those would become a thumb. In short, this is what that would look like in HTML:
<rangegroup>
<legend>Temperature Range</legend>
<label>
Minimum Temperature
<input type="range" name="temp-min" value="-25">
</label>
<label>
Maximum Temperature
<input type="range" name="temp-max" value="15">
</label>
</rangegroup>
What exactly is happening here? A lot, and I’m sure with a bit of browser engineering magic that this could look different, but this starting point does make a few things clear regarding the direction of this API.
Look at the <rangegroup>
as sort of a <fieldset>
; this <fieldset>
has a <legend>
which could become the general label for your duo-thumb range slider. Giving each thumb a <label>
can help screen readers to identify the intent of each thumb. In complete honesty, I haven’t tried this in every piece of software, but inside the prototype, this is working rather nicely. Which is why I also did not add “crossing” of thumbs. I’m not saying it is impossible, but when a thumb has a “minimum” label attached and is suddenly passed the “maximum”, it’s weird….
A progressive enhancement?
I would love to bring this idea to the table. Having a way where we could progressively enhance for most scenarios. By using this wrapping element there is a possibility to have two individual range sliders for browsers that don’t support <rangegroup>
. So, depending on the use case, there is a chance of progressive enhancement here that I believe should at least be explored.


Why range sliders as a progressive enhancement?
Why not <input type="number" />
?
I believe using <input type="range">
elements better preserves the design intent. A range input is designed for selecting an approximate value within a scale, where the user is more interested in the position along the track than a precise number. This means that using <input type="range">
as the fallback provides a more equitable, if not identical, user experience.
Min and max values
Since range inputs can have a min
and max
attribute, I thought it would be handy to extend capabilities by allowing constraints by the range group. This is one of those examples where progressive enhancement might not work anymore, but I don’t want to miss this opportunity at the starting point.
- If a handle’s range is within the group’s range (e.g.,
rangegroup max="100"
,input max="70"
): The track will render from 0 to 100, but the handle will be prevented from moving past 70. This is a desirable pattern for use cases like a seek bar for a live video stream, where the total buffer is visible but the user cannot seek into the future. - If a handle’s range exceeds the group’s range (e.g.,
rangegroup max="100"
,input max="200"
): The handle’s movement will be clamped by the<rangegroup>
’s bounds. The handle will not be able to exceed a value of 100. This ensures the component’s visual representation is the source of truth and prevents invalid states.
Stepbetween
It might be nice to define a boundry on how close thmbs can be against each other, this is where the stepbetween
attribute would come in. It defines the minimum distance between handles in a range group.
Styling capabilities and datalist
In the current explainer, there are a few styling capabilities that I think we all want to have. My main background is in UI/UX, so I am aware that this explainer is not complete and has the focus there, but we need to start somewhere. The same pseudo-elements and classes defined in the new CSS Forms spec should be there, but there are a couple of nuances/extras.
Here is a short explanation:
::slider-thumb(*)
: would style the thumb, between the parentheses, a number can occur for each thumb:slider-segment(*)
: This is a pseudo-class that styles a segment of the::slider-track
the first one between edge and first thumb, the second between the first and second thumb, etc…::slider-tick
: Optional tick marks along the track for value representation. (when datalist is paired.)::slider-tick-label
: Labels associated with tick marks. (when datalist is paired.)
I still have a lot of unfinished thoughts about the tick marks as well. For the moment, I’m leaning towards an idea that sort of works like CSS carousels, where the ticks would be wrapped in a ::slider-tick-group
. But as I said… Still a lot to think about
What I do know is that <datalist>
pairing should be supported.
More than two thumbs?
I love the idea of having the capability to add more than two thumbs, which is actually part of the foundation of this API idea. Having the chance to add more range inputs for more thumbs.
I added a few examples of how it could be used in my prototype, but this is why I need the community: Let it be heard: Do you want this? Why do you want this? Do you have examples of where you would use this?
Here is another one of my ideas: an opening hours slider:

This would result in something like this:
<rangegroup id="opening-hours-range" min="480" max="1320" list="hours-ticks" stepbetween="30">
<legend slot="legend" class="color-purple">Opening Hours Selector</legend>
<label>
AM Open
<input type="range" value="540" />
</label>
<label>
AM Close
<input type="range" value="720" />
</label>
<label>
PM Open
<input type="range" value="780" />
</label>
<label>
PM Close
<input type="range" value="1020" />
</label>
</rangegroup>
<datalist id="hours-ticks">
<option value="480" label="8 AM">
<option value="540" label="9 AM">
<!-- etc -->
<option value="1260" label="9 PM"></option>
<option value="1320" label="10 PM"></option>
</datalist>
rangegroup::slider-segment(1),
rangegroup::slider-segment(3),
rangegroup::slider-segment(5) {
background-color: oklch(35% 0.02 230); /* Muted track */
}
rangegroup::slider-segment(2),
rangegroup::slider-segment(4) {
background-color: var(--color-teal);
}
rangegroup::slider-thumb {
background: var(--color-teal);
}
Expanding…
I thought a lot about what should be the default and what should not be. I think that if we want to see the value inside the thumbs, anchoring could be used to put the values on top of the thumb. Showing live updated values could be handled by a bit of extra JS. There are quite a lot of possibilities here.
The following examples anchor values on the slider. This is also using the same component:
There is a lot more detail on all of this that you can find in the explainer. But this article is already becoming a bit too long…


And this is why I need you
I know there are still a lot of open questions and things to be improved, which is exactly why this is so important now.
I am not a browser engineer; I am a developer creating web applications. I’m not even sure if I’m an expert on anything, really, but I do love the web. I usually ask the stupid questions, which sometimes actually is the good kind of question. I am NOT going to build this API. I haven’t got the skillset. Which is why…
I need it to be on the radar, on the radar for people who can make this happen. I need you to ask for this in your socials, write about this, anything, really… Make sure it can’t be ignored.
All I can promise you in return is that I will keep asking the stupid questions, and will be testing the API in the future, making demo’s trying to break stuff. See me as your little helper, who might not really be qualified to work on web standards, but just really cares about it.
This being picked up is the most important thing.
And if you read the explainer, you can also help by filling out this feedback form.
Thank you 🙂