-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When multiple slider thumbs are visually collapsed, the thumb with the highest index captures all pointer interaction. #6408
Comments
Thanks for bringing this up, it looks like a bug/bad experience. Adobe products have many multi thumb slider, such as our gradient creation in photoshop. |
An interesting idea, but I wonder if this affect users who would want to predictably control/restrict the value of specific thumbs (e.g. you have three thumbs and you programmatically track the current value of each. What if you had logic that assumed that the middle thumb would never exceed the value of the surrounding thumbs? Would it be weird if the middle thumb you were tracking became one of the outer thumbs?). Not sure if thats a non-issue, will have to think on it more. As an aside, I found this older issue with a workaround which perhaps we could add to the hook/docs. It doesn't give as much flexibility as letting each thumb slide past any other thumb, but does help with the min/max case at least |
I think if we take the value of a multi-thumb slider to be the sorted values of that slider's thumbs, then any code that assumes that values are in ascending order would still work. The only thing that would change would be the end user's experience.
I admit that this particular case may feel slightly weird, especially if you're operating a complex slider with different kinds of thumbs whose semantics go beyond just "start of range" / "end of range". But how often does that actually happen? I'd guess that simple range sliders with two thumbs easily make up > 90% of the use cases for multi-thumb sliders. And while I'm not all that familiar with Adobe's software ecosystem or UX design principles, as a long-time Computer Toucher, I have an intuitive sense that range sliders should allow swapping thumbs. Every other component library I've found that supports range sliders — including MUI and Ant Design (the most popular and second most popular React component libraries), as well as MUI Base and Radix UI (AFAICT, RAC's only competitors in the unstyled component library space that support range sliders) — allow swapping thumbs. If Spectrum wants to default to non-swappable thumbs for Adobe-specific reasons, that's fine, but I'd expect that as a general-purpose UI framework, RAC should default to the overwhelmingly more popular option. (Also, as far as implementing really complex sliders is concerned, allowing swapping would actually increase the space of what's possible. I can imagine complex multi-thumb sliders where the different kinds of thumbs are required to stay in a specific order, but I can also imagine complex sliders where you'd want to be able to reorder the thumbs, which I think isn't currently possible to create in RAC. @snowystinger's example of a gradient creator, for example, actually seems like it would benefit from allowing swapping? Perhaps there should be three possibilities: (a) forbid swapping (the current behavior), (b) allow swapping thumbs but keep the thumb values sorted (what I propose should be the new default), and (c) allow swapping thumbs without sorting. That last one seems very niche, though, and perhaps should be its own issue.)
Ah, thanks for linking that issue! I did find that workaround shortly after I submitted the initial draft of this issue, and as I noted in the edited issue description, it only works as long as you maintain focus on the thumb; click away just once, and the problem returns. There's nothing wrong with that workaround being in Spectrum — if nothing else, it looks nice to have the currently active thumb appear on top of any other thumbs it might overlap with — but as it's a partial mitigation to part of the problem, I'd hesitate to recommend it to users of RAC. |
Another data point: the Spectrum Web Components implementation of a multi-thumb slider also defaults to allowing swapping while allowing customization to prevent it. Their API looks pretty good — might not be a bad idea for RAC to emulate it. |
First, thank you for all your thoughts/feedback. I think there is a problem here which needs more immediate solving than anything else. The thumbs can get stuck at the end of the range. That is unusable to a mouse or touch user. This should be solvable by changing the z-Index when at the end of the range. There are other improvements that can still be made in regards to stacked thumbs in the middle of the range. I think we can consider those separately. As pointed out, #6338 There seem to be a lot of topics going on now in this thread. I think at the top level we have
RAC is a range slider, we have not built a non-relational slider, so I'm not going to address that here other than to say you can drop down to our hooks to implement one of these if you want. I don't think it makes sense for the handles to go past each other in a range slider, it creates a few different problems:
Overwhelmingly more popular to whom? Do we have user studies on this? If not, I'd default to the reasons I listed above for not doing it. Popular does not mean correct and I'd challenge this one. |
I don't have user studies, but that isn't the only way to gauge popularity. I spent some time this afternoon searching for libraries that implement multi-thumb sliders (most general-purpose component libraries don't), prioritizing the popular ones; for each one, I noted whether it defaulted to allowing or prohibiting swapping thumbs, and how many GitHub stars it had. (To keep the scope reasonable, I limited my search to libraries for the web, and ignored the ones that either had very few stars or had obviously broken implementations; for GitHub star counts, I ignored things that could plausibly be considered duplicates, like MUI and MUI Base or Ant Design React and Ant Design Angular.) Clearly, this is by no means a scientific study, but I think it's fair to treat the results as at least somewhat indicative. Libraries that default to allowing swapping [edited to fix some links I got wrong the first time]:
Libraries that default to prohibiting swapping:
In total, based on maybe an hour of research, 60% of libraries — representing 72% of total GitHub stars — default to allowing swapping. On that basis, I retract my earlier statement that swapping is the overwhelmingly more popular option — but I nevertheless maintain that it is the more popular option. Again, I want to emphasize that I don't think that this methodology is a scientific measure of popularity, nor do I think that popularity is in any way a measure of correctness. I do, however, think that this methodology gives a rough indication of popularity, and that when it comes to UX, popularity should be a consideration. A part of accessibility is implementing patterns that are going to feel intuitive to people, and people's UX intuitions are formed in no small part by their interactions with existing software. To your point about "relational" vs. "non-relational" sliders — that seems like a very specific interpretation of a range slider's semantics, and not one that every user is going to share. Sure, you could say that the two thumbs of a range slider represent the minimum and maximum of the range (and are therefore distinct), but you could just as easily say that they represent the two endpoints of the range (and are therefore fungible). If you're buying a ticket, and the ticket agent tells you they have some availability in rows thirteen through nine, you presumably understand what they mean just as easily as if they'd said rows nine through thirteen, no? Returning to UX, I think it's fair to say that being unable to do something you expected to be able to do generally makes for a worse experience than being able to do something that you didn't expect to be able to do. A user who expects to be able to swap thumbs and observes that they can't is liable to feel some frustration; a user who expects that they won't be able to swap thumbs and observes that they can is going to shrug and get on with their life. To riff on your taxonomy of what the issues are here, I would say that we've discussed three potential sources of user frustration:
I'll grant that the first is a bigger problem than the second, which in turn is a bigger problem than the third. The reason that I'm advocating for allowing swapping by default is that it handily solves all three problems in one stroke. The main objections seem to be that it would be difficult to implement, and that it violates an abstract notion of correctness. My response to the first objection is to point to all the libraries that presumably had to deal with similar difficulties, and opted to implement swapping anyway; my response to the second objection is that where there exist multiple competing notions of what the correct semantics are, it makes sense to err on the side of the one that puts more power in the hands of the user. Anyway, I don't want to get into a drawn-out argument; I've made my case, and you're welcome to take it or leave it. If you decide that you are interested in implementing swappable thumbs, I'd be happy to volunteer to take a stab at an implementation. |
Thanks, I'll bring it up with the team for more opinions. Side note, MUI's implementation actually swaps the two handles. This leads to some interesting announcements with VO. I haven't checked the rest. But at the very least, MUI's appears to be an intentional feature. |
Relevant issues on other libraries: Team thoughts were: |
+1 for having the option to slide thumbs past each other. I don't think it should be the default but the option would be nice. My current use case for it is a gradient slider with thumbs for each color in the gradient with their position in the slider representing their stop position within the gradient. Pretty niche but it's kinda limited by the thumbs not going past each other. One alternative compromise would be having the option for thumbs to push each other based on a proximity threshold set as a prop. This could also help with the current bug where 2 thumbs can get stuck at the ends. I believe the Mantine library handles it this way. An example could be a proximity limit of 10 units and when a thumb's value is within 10 units of another, any movement in that direction would also move the second thumb to maintain the min distance between thumbs. |
Hey 👋 I was looking for a way to swap slider handles while using RAC and found this issue. After reading it and looking briefly at #6532, I wonder if any blockers prevent us from fixing this. I am happy to offer my help if I can. |
Provide a general summary of the issue here
Suppose a user is looking at a slider rendered with
<Slider min={0} max={100} value={[50, 50]} {...etc} />
, and wants to change the currently selected range from[50, 50]
to[25, 50]
. Because both thumbs are initially at50
, the slider appears to have just one thumb.One might expect that clicking on that thumb and dragging it to the left would change the selected range, but it does not, because it's the second thumb that gets the pointer events, and that second thumb can only be dragged to the right. If our hypothetical user wants to use the thumbs to change the selected range from
[50, 50]
to[25, 50]
, they would need to:[50, 50]
to[50, n]
for some value of n between 51 and 100.[50, n]
to[25, n]
.[25, n]
to[25, 50]
.Usually this is merely annoying, but it gets particularly nasty if both the thumbs are set to the slider's maximum value, e.g.
<Slider max={100} value={[100, 100]} {...etc} />
. In that case, both thumbs will be collapsed at the end of the slider's track; clicking on that collapsed thumb selects the second thumb, which cannot move at all. In this state, the slider appears completely stuck. It is possible to escape from this state by either clicking on the slider's track or using keyboard controls, but these workarounds may be far from obvious to an end user.🤔 Expected Behavior?
When both thumbs in a range slider are collapsed to the same value, it should be possible to click on that collapsed thumb and drag it in either direction.
😯 Current Behavior
When both thumbs in a range slider are collapsed to the same value, it is only possible to to drag it to the right — or not at all, if that value is also the slider's maximum.
💁 Possible Solution
Neither Radix UI not MUI Base have this bug; both of those allow the two thumbs of a range slider to swap positions.
That said, those libraries only support one-thumb and two-thumb sliders, whereas react-aria supports sliders with an arbitrary number of thumbs, which does complicate things. (I am kind of curious — how often are sliders with more than two thumbs actually used? It seems pretty niche.) [Edit: I was mistaken; Radix also supports multiple thumbs.]
I think the cleanest solution would be to remove the restriction on thumbs moving past their neighbors — allowing any thumb to move to any value — and having the value of a multi-thumb slider be equal to the sorted values of its thumbs. I think this should be the default behavior; perhaps the current behavior, where thumbs are restricted from moving past their neighbors, could be enabled with a prop.
Edit: I noticed that react-spectrum includes a partial workaround for this. If a thumb is in focus, it gets a higher z-index, which means that if you drag both thumbs to the same value, the next time you click on that visually collapsed thumb, you'll target the last thumb you used. This can help to keep the thumbs from getting stuck at one end of the slider — but only as long as you maintain focus.
🔦 Context
See also mui/material-ui#6338 for more reasons to allow thumbs to swap positions.
🖥️ Steps to Reproduce
Or:
Version
latest
What browsers are you seeing the problem on?
Firefox, Chrome, Safari
What operating system are you using?
OS X
The text was updated successfully, but these errors were encountered: