Native dual-range input
256 points
21 days ago
| 17 comments
| muffinman.io
| HN
maxlin
21 days ago
[-]
This kind of slider should ALWAYS have the middle part movable; IE grabbing it would move both handles at the same time.

For reference this is how Unity does it: https://docs.unity3d.com/StaticFiles/ScriptRefImages/EditorG...

reply
worthless-trash
21 days ago
[-]
As a counterpoint, i would never have clicked the middle part, the current view in my mind was that this was a modified slider, not another new widget entirely.

"ALWAYS" might be a bit of an overstatement.

reply
stankot
21 days ago
[-]
Hey, author here, glad to see it popping up on HN.

I see people started opening issues and leaving bug reports here. I’ll try to go through them tomorrow (it is getting late here).

I created it because I needed it for my generative drawings. I prefer dragging a slider and seeing how the image changes, more than typing in a number.

I really tried to keep it minimal.

reply
bartvk
21 days ago
[-]
Goshdarn I love this post. I enjoyed my morning coffee while looking at the calculations, and the description of the debugging mode. It's a clever usage of native components. Currently my experience is with SwiftUI and it's almost too easy to make your own components. However that doesn't make it the best option as you described, native components are often very full-featured. I checked your post on Firefox on iOS, which is arguably an obscure browser, and it worked fine.

Very well done.

reply
stankot
20 days ago
[-]
Thank you, comments like yours really make my day!
reply
lilyball
21 days ago
[-]
Playing around with this and immediately hit a bug. If I drag the sliders to 100 - 100 and then try to do 99 - 99, I can't. I can't get there from 99 - 100, and I can't get there from 98 - 99. The only way to get to 99 - 99 is to drag the lower bound somewhere lower than 98. If I'm at 98 - 99 and I drag it down to 97 - 99, then I can get to 99 - 99.

This bug can occur anywhere, it was just easiest to hit at 99 - 99 because that's right next to one of the ends of the slider. More generally, if I get to any X - X, then I drag one end of the slider by 1 step, I can't drag the other end of the slider into that gap. The only way to close that gap is to drag the other end further away first.

reply
stankot
20 days ago
[-]
Nice catch! Actually I thought of this and it works in Chrome and Firefox, but it seems that Safari is not triggering the focus event on mouse down, but only when you start moving the slider. Thank you for the report, I'll make sure to fix it.
reply
stankot
20 days ago
[-]
I just released a fix for it and updated the blog post.
reply
Arnavion
21 days ago
[-]
100-100 -> 99-100 -> 99-99 works for me in Chromium on desktop Linux.

I do have a different visual bug. If I start at 23-25 and then drag to 24-25, the right knob at 25 shifts by a few pixels. Drag the left knob back to 23 and the right knob also shifts back.

reply
lilyball
21 days ago
[-]
Ah yes I should have specified browser engine. My bug was in Safari on macOS.
reply
encoderer
21 days ago
[-]
^ and this is why I love making developer tools.
reply
Y-bar
21 days ago
[-]
This is cool! I have always thought that the HTML <input type=range> input needed a dual-value implementation because that makes a lot of sense. Consider the use case "I want to filter products with at least X widgets but no more than Y".

However, I found a bug in Firefox I want to highlight:

Any time I click on a min or max handle they change change the value one step up or down.

If I make an effort to click in the dead center of the handle it does not change. If I click slightly to the left the selected value will decrease one step. If I click slightly on the right side of the handle it will increase.

I would expect the value to _only_ change when I make an actual action to change it by moving my mouse pointer with the button held down.

reply
stankot
20 days ago
[-]
Honestly, I don't think that is a bug. All examples are quite dense and the thumb covers multiple steps on the track. Firefox then translates every click like you clicked directly on the track. The library doesn't interfere with it in any way, it is how Firefox works.
reply
Y-bar
20 days ago
[-]
Sometimes it even goes two steps in this implementation. Given that a vanilla <input type="range"> never moves (manually tested in Edge, Firefox, Chrome, Safari now) the handle when clicking anywhere on the handle I would absolutely expect this implementation to work the same.
reply
jasonlotito
20 days ago
[-]
The fact that this works with keyboard is wonderful. It correctly works, too, meaning I can hold shift-tab to move backwards. Wonderfully done. That's such a small thing, and I just wanted to express my gratitude for getting that interaction correct.
reply
hokkos
20 days ago
[-]
For my company design system, an intern came up with a side by side POC like that but there was always pixels from one input jumping a bit and we couldn't make it work, so a second intern came up with a solution with 2 overlapping input range.
reply
echoangle
21 days ago
[-]
Very cool, I always used the jQuery UI slider when I needed a range input, which forced me to add jQuery and jQuery UI to my page, just for a single slider. This is very nice!

Edit: is there a chance to get a premade plain JS file to use, instead of an ESM module?

reply
tln
21 days ago
[-]
You can grab this and then remove the "export default" line at the end.

https://cdn.jsdelivr.net/npm/@stanko/dual-range-input@0.9.8/...

Don't forget the CSS

https://cdn.jsdelivr.net/npm/@stanko/dual-range-input@0.9.8/...

reply
cosmotic
21 days ago
[-]
Is this the right place to report bugs? The handles in the first two examples trap touch interaction blocking scroll. The latter three examples don't. This has a side effect of not being able to 'drag up to reveal the labels underneath ones fingers since it just scrolls the page, keeping the labels underway the finger.
reply
stankot
20 days ago
[-]
If you can replicate this, please open a github issue [1].

Which browser and OS are you using? Because this library doesn't do anything regarding the scroll blocking (because it is using native inputs). On my phone (iOS) scroll is blocked on all input[type=range] elements, styled or not.

[1] https://github.com/Stanko/dual-range-input/issues

reply
Rygian
20 days ago
[-]
> The "native" part is somewhat open for discussion. I call it native because the library uses two native HTML range inputs. This means that all of the native interactions and accessibility features are preserved.

My dividing line is: if it needs Javascript to work as intended, it's not native anymore.

reply
onli
20 days ago
[-]
I agree. And I think that's the common usage?

I still get what the author is aiming at though, using combined regular sliders instead of implementing a div soup animated by js moved this a lot closer to a native solution. Probably closest it can be, if the javascript can't be replaced by clever css.

It's still a very useful widget to have available, and that space was missing implementations. Native or not.

reply
extra88
20 days ago
[-]
Usually but it's not entirely clear cut. The <dialog> element is native but you have to use JavaScript to open it in the modal state. Before the popover attribute, you couldn't open it at all without JavaScript.

There are also native, vanilla JavaScript methods for things like form validation that I would consider distinct from a library that doesn't use the browser's internal validation tooling at all.

reply
Intermernet
20 days ago
[-]
Thankyou! I was looking for this when I created https://spodj.intermer.net/

I ended up having to use react badly to get the functionality I required as I'm a terrible front end developer.

reply
fitsumbelay
21 days ago
[-]
for my local install of codemirror I styled a (single) range control as the drag-to-resize border between my editor iframe (on the left) and my preview iframe (on the right) and was about to get into doing the same for the individual html, css and javascript editor iframes within the editor iframe. so I'm looking forward to seeing whether this component will be a one stop shop for that solution. thanks for this, OP
reply
bmacho
20 days ago
[-]
Clever!

It probably can be made to work javascript-less, just make the CSS width-calculation more sophisticated, and dependent on the slider values.

reply
rpastuszak
20 days ago
[-]
> dependent on the slider values

That’s the tricky part for a JS free implementation, right? Or am I missing something?

reply
Y-bar
20 days ago
[-]
I think they are suggesting using something like this, which does work to target certain attributes:

input[value="5"] { width: 20%; }

This could then be combined with the sibling selector to target the other one

input[value="5"] + input[value="11"] { width: 80%; }

Though I am unsure how to make it entirely workable (you probably need a simple event listener to set the DOM node value to the dynamic form value). Interesting exercise if nothing else, and I think it could be doable to reach a working solution.

reply
stankot
20 days ago
[-]
I think it can be theoretically done, like it is mentioned in the comment above, but you would need a new block of CSS for every slider min/max/step combination. It feels it would be harder to maintain than the javascript version.
reply
KTibow
20 days ago
[-]
Plus it needs JS to work (the DOM's value has to be synced with the attribute value for this selector to work)
reply
rpastuszak
20 days ago
[-]
Yeah I was thinking about something similar, e.g. using attr()* and a pseudoelement to pass the value from DOM to CSS of a ::before/::after pseudo-element.

But that still feels like asking for trouble:)

Luckily I need to leave the house now, I'm feeling CSS naughty.

* IIRC support for anything besides `content:` is still very unstable.

reply
rafram
21 days ago
[-]
This is very neat! Nice work.
reply
tobyhinloopen
20 days ago
[-]
Neat! I love this
reply
kn100
21 days ago
[-]
totally pointless to implement this honestly but I was disappointed it didn't support multi touch :p
reply
corytheboyd
21 days ago
[-]
Very clever!

Totally unrelated to this project, just a general UI question: does anyone like these inputs? Every time there is a number input next to one, I use that instead. Seems the upper limit of “ticks” you can have on one before it becomes unusable is like… 10?

Proper number inputs support all the same features (min, max, arrow keys to increment/decrement), but you can also just input an exact number. The range does visualize min, max, and current value relative to those nicely, but it’s annoying to actually use as an input more often than not.

The only real exception is for ranges of 0-100 type things, where the exact value doesn’t need to be precise, just roughly somewhere on that 1-100 scale. Eyeballing it is enough here, you don’t feel frustrated that you can’t use your thumb to get exactly 71. Volume slider, etc.

reply
yreg
21 days ago
[-]
> does anyone like these inputs?

We've A/B tested a slider against a textbox with plus and minus buttons (banking, on mobile) and the latter seemed to work better (as in fewer users cancelled the flow).

I'm not pretending this finding can be generalised, though.

reply
Rygian
21 days ago
[-]
I can't imagine a banking interaction where the amount of money is not a precise value.

What use cases motivated the testing of a slider?

reply
lmm
21 days ago
[-]
Wonga.com was (briefly) a huge success story with their "two slider" interface. Perhaps because it made it easy to see how the output changed with the input.
reply
yreg
21 days ago
[-]
I believe it was some mortgage calculator and it jumped by 10k steps.
reply
encoderer
21 days ago
[-]
I could make the argument that a number input plus a labeled slider is superior to number input plus a text label of min/max
reply
corytheboyd
21 days ago
[-]
Makes sense to me, the range input is effectively acting as the label here, it just happens to be an input as well. Best (better?) of both worlds.
reply
wruza
21 days ago
[-]
I almost never use them. In sd webui I change resolution often, so I patched some divs to contain [512, 640, 768, …] and click these instead. Not sure if this slider control should even exist in a flow context, because it cannot be made scrollable like a volume range.

I also somewhat like unix style numeric inputs because you can grab a bar between the arrows and drag it to change the value. No long range required.

Ranges with sticky points are somewhat okay, e.g. Virtualbox settings stick to 2^n values for RAM and some integer disk GBs. But these intermediate values are just nonsense and nobody ever selected 7527MB of RAM by non-mistake.

Bonus points for Ubuntu keyboard repeat/delay settings which don’t show the numeric values at all. You set delay to 178 or maybe 223 or maybe 202. Who cares about muscle memory, right?

reply
zapparoni
20 days ago
[-]
Anytime you don't care about exact values and want a quick way to nudge the value in a live visual environment they are great.

For example in an editor for procedurally generated stuff like random maps, texture, sounds, etc.

reply
jcelerier
20 days ago
[-]
> does anyone like these inputs?

I implemented one in https://ossia.io but in practice a draggable spinbox is much more useable

reply
throwaway14356
21 days ago
[-]
The native slider is hideous as f and further offends me by being called a range. Why are stupid simple things missing like display the value? We could even have a same name number input that displays the set value or an <input for=""

html forms in general got very little love. They should be taken to the drawing board along with sql and get some relation therapist to blame the earlier for the endless fighting. over the years of growing up together json made an effort to make the marriage work but html forms are very stubborn and unreasonable.

Things actually got worse when pressing the back button erased the fields. What we wanted was a way to put the same form with the same values back on the page after failed validation. I have backends where that stuff takes up 60% of the code. imagine <form src="foobar.json"/> with a nice widget displaying the key value pairs, with outlines for nested fieldsets?

anyway, thanks for the nice dual slider. my own experiments didn't result in something nice enough that i would dare use.

I would like to see a contest with cash prizes for designing better html forms with backwards compatibility. Winning entries should be put in the spec. Im sure we would pay plenty if it would ease the suffering. :)

reply
wruza
21 days ago
[-]
And then some wonder why people resort to js-controlled spas and tend to forget how they cursed after their “simple html form” deleted input due to navigation or accidental refresh. Input is the most valuable data in a program because it cannot he recalculated and usually reqiures work to produce. Anything that doesn’t get this principle sucks.

That said, I don’t think src=form.json would help. Some type of a local permanent storage is basically required for app-level interaction, because the page state is so transient and fragile. I’d say it should be <form storage="foo."> and all controls would be saved as foo.<name> into localStorage. With <form storage="foo." reset> received from backend to reset it explicitly if needed.

reply
whywhywhywhy
20 days ago
[-]
Most egregious thing is many times when people roll their own forms they end up actually removing things. The amount of forms I encounter where autofill and spellcheck are broken is crazy.

Maybe it’s some “best practice” library popular in the react ecosystem, I see it often enough to suspect that but autofill and spellcheck are my input and my business and a form shouldn’t decide if they’re enabled.

reply