open-ui icon indicating copy to clipboard operation
open-ui copied to clipboard

[Range] Thumb collision handling

Open brechtDR opened this issue 10 months ago • 9 comments

When multiple handles are present in a range input, we need a clear strategy for handling thumb collisions. In case handles start to get close to each other it might be hard to use the pointer and select the right handle.

Options to consider:

  • Preventing thumbs from occupying the same position
  • Visual stacking of thumbs (but then: which thumb appears on top?)
  • Implementing a minimum distance between thumbs
  • Implement "pushing" behavior where one thumb pushes the other based on the size defined in CSS?
  • Allow thumbs to pass through each other, which might open up a whole lot of other problems, but wanted to at least add this as an option. A strong use case would be needed for this though

Questions:

  • Should collision handling be configurable, or should we define a single standard behavior?
  • How to handle edge cases like programmatically setting values (via JS) that would cause collisions?

brechtDR avatar Apr 03 '25 12:04 brechtDR

Configuring would be preferable but seems complex. By default, I suggest allowing overlap and pass through since it seems simplest. When they overlap, the user can use tab+arrows to move or just move the overlap out of the way to access the other handle.

sorvell avatar Apr 18 '25 00:04 sorvell

@sorvell Very interesting thought. I personally see benefits in both use-cases and that's why I wanted to present this to the group. I think many users won't know how to "get out of a pinch" when they overlap using a keyboard.

I do feel like configuring for passing through should be a thing from a UX perspective, but I agree with the complexity.

brechtDR avatar Apr 24 '25 09:04 brechtDR

I feel like this falls into a similar category as say typing letters into a number input or having a value that's too big.

Browsers vary in how much they prevent the user making mistakes.

It's possible this should just be implementation defined. The main thing we do need to specify is whether it's a validation constraint that they don't pass through each other. Is thumb 1 < (=??) thumb 2 a validation requirement.

I'm also curious if the browser prevents the thumbs overlapping is there an a11y issue with not having a way to explain that. I've read that typing letters and losing them to the browser is a potential issue, is this similar?

lukewarlow avatar Apr 24 '25 11:04 lukewarlow

Some other things to consider that make this issue, at least to me, surprisingly complex.

Overlapping thumbs could be shown side-by-side un-overlapped. This might be fine when there's enough space between tick marks, but if not, the thumbs could seem to be at obviously wrong positions. They could be vertically stacked un-overlapped, but this seems odd and would need a lot of extra space.

If more than 2 thumbs is supported, multiple thumbs could overlap.

If the the thumbs are allowed to be shown overlapped, how can you use a pointer to select the other thumb? Note that in Material Design, the direction of the drag dynamically selects which thumb you are moving.

sorvell avatar Apr 24 '25 15:04 sorvell

I think some of these questions might need use cases and existing example research to answer fully.

lukewarlow avatar Apr 24 '25 15:04 lukewarlow

All my two thumb sliders overlap. Both because it's easier to code that way, both because I often want to reverse the direction of an interval.

For example: I code interactive demos to make it easier to understand various concepts.

Let's say I want to allow picking what the input alpha of a filter maps to. For example, I have an element that's basically a gradient from fully transparent on the left to fully opaque on the right.

.my-elem {
  background: linear-gradient(90deg, #0000, red)
}

This element gets an alpha manipulation filter applied and I allow tweaking this filter via a two thumb range input that decides what alpha the fully transparent end (alpha = 0) of the gradient maps to (thumb 1) and what alpha the fully opaque end (alpha = 1) maps to (thumb 2). Basically, the first value in tableValues is given by thumb 1 and the second one by thumb 2.

In this case, I never want for the thumb 1 value to be limited to being smaller than the thumb 2 one. And I definitely don't want pushing (a thumb's value getting modified when it's not my intent to so do). Not against adding such options, but they need to be options I can opt out of.

For such a demo, I may often want the originally fully transparent end to map to an alpha of .75 (value given by thumb 1) and the originally fully opaque end to map to an alpha of .25 (value given by thumb 2).

svg
  filter#alpha
    feComponentTransfer
      feFuncA(type='table' tableValues='.75 .25')

I could also have three thumbs in order to map not just the 0 and 1 alpha points, but the 0, .5 and 1 alpha points:

svg
  filter#alpha
    feComponentTransfer
      feFuncA(type='table' tableValues='.3 .7 .1')

In this particular case, the values of thumb 1 (.3) and thumb 2 (.7) are bigger than the value of thumb 3 (.1).

I navigate in between thumbs using tab. Arrow keys are used for moving the thumbs, so...

I make the currently mouse dragged/ focused thumb be on top. If they overlap and want to move one of them, I almost always move it with the arrow keys.

I don't think collisions are something that should be handled in any way. The same value for both thumbs may well be the desired outcome. Like it was pointed out above, cubic-bezier() handle values.

thebabydino avatar May 01 '25 15:05 thebabydino

The Open UI Community Group just discussed [Range] Thumb collision handling.

The full IRC log of that discussion <keithamus> q+
<sorvell> q+
<hdv> brecht_dr: this is about thumb collision handling on range input types
<hdv> brecht_dr: there were some solutions in the issue already
<hdv> brecht_dr: we might also look at making that configurable
<masonf> ack keith
<masonf> q+
<hdv> keithamus: if we have a wrapper el I think min and max on the wrapper to set all bounds for the els inside… to avoid overlaps you could set mins and maxes on the individual ranges
<masonf> ack sorvell
<hdv> keithamus: and then allowing overlap would just be done by leaving out the mins and max
<bkardell> q+
<hdv> s/mins/min
<hdv> sorvell: not allowing overlap is incredibly limiting… depending on the amount of checkmarks it could render wrong, it's impractical to not allow overlap
<hdv> sorvell: once you allow overlap you could get a huge UX problem
<hdv> sorvell: good UX libraries understand the direction user might want to go …super gnarly to get right (I implemented this in Material)
<bkardell> q-
<hdv> sorvell: in other words, this issue is tricky and we need to get it right
<hdv> masonf: +1 to what Keith said and allow all for v1, and in v2 potentially figure out what people want and make it better
<hdv> masonf: thanks all
<hdv> Zakim, end meeting please

css-meeting-bot avatar May 01 '25 19:05 css-meeting-bot

Tentatively removing agenda+ please re-add if this needs further discussion.

lukewarlow avatar May 07 '25 17:05 lukewarlow

There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.

github-actions[bot] avatar Nov 04 '25 00:11 github-actions[bot]