-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[Button][material-ui] Improve buttons' text selection #38158
Conversation
Netlify deploy previewhttps://deploy-preview-38158--material-ui.netlify.app/ @material-ui/core: parsed: +Infinity% , gzip: +Infinity% Bundle size reportDetails of bundle changes (Toolpad) |
A few problems I can spot to not regress on #8 (double click on button shouldn't select it) where I think that we still need the style:
|
@oliviertassinari I'm not convinced we should do so. I lean towards relying on the browser's default, my reasoning (tested on Chrome): Regarding
|
@DiegoAndai This is where I'm coming from as well. The cases I raise are cases where we don't respect the browser's default, which is if I look at Chrome, Firefox, Safari, on macOS and Windows, in the majority vote:
and this regardless of the disabled state (it's still a button element you might try to spam click on) or the host element (it's still a role="button").
We have done way bolder design changes in the past without pushbacks, I think it's safe for a patch release (bug fix). |
This connects to #20700 as well. |
@oliviertassinari you convinced me, I'll implement these changes Regarding the host component, do you think using the |
@DiegoAndai I think that it boils down to the onClick handler, for case people double click too quickly. The role button sounds like a good way to identify it 👍. For example, if it's a link behavior that looks like a button, what would we want? I guess the regular double click text selection. |
8a80e59
to
763a4b5
Compare
I've been able to implement the expected behavior:
For the Material Button in the following cases:
Non
You can check what I've got so far here: https://deploy-preview-38158--material-ui.netlify.app/experiments/material/button-select @oliviertassinari I'm stuck here, any ideas? If you want to check out how I implemented the behavior, it's in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oliviertassinari I'm stuck here, any ideas?
I wouldn't go further. I think it's as good as it can be.
I could spot two other things:
- Joy UI
<Button component="span"
should get pointer-events, the same logic as Material UI IMHO. - We could use a
:not([type="button"])
CSS selector, but it would be a breaking change, increased specificity, so probably not ideal:
[`&.${buttonBaseClasses.disabled}`]: { | ||
cursor: 'default', | ||
...(!isButton && { | ||
pointerEvents: 'none', // Disable link interactions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A guess it's why we do this?
pointerEvents: 'none', // Disable link interactions | |
pointerEvents: 'none', // Prevent double click text selection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the other way around. pointer-events: none
is used here to turn off pointer events (on-click
, on-mouse-down
, etc.) in case the element is not a button
(the button
element disables them natively when disabled
).
The side effect is that double-click selection is enabled, which is unfortunate. I couldn't find a workaround for this.
So the comment "Disable link interactions"
is correct. It could be more general "Disable interactions"
as it does apply for any non button
element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarification: pointer-events: none
does not enable double-click selection by itself but rather prevents us from handling text selection in non-button
elements:
To turn off only double-click selection, we can use
.&:active {
user-select: none
};
This way, user selection is only disabled when clicking (active
state), but not when dragging from outside the element. But with pointer-events: none
, we don't get the active
state, so we cannot use this trick.
Using user-select: none
without the active
state selector is not a good option as that turns off both double-click and selection dragging from outside.
And this is what I couldn't find a workaround for. The best (not perfect) solution would be having the behavior we want for all variations except for disabled non-button
elements. Those are the ones that require pointer-events: none
. For those, I propose enabling all selection, which is better than no selection, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, pointer-events: none
does break the native button
handling of text selection, enabling double-click selection, so we shouldn't add pointer-events: none
to button
elements. It's also not necessary on these, as pointer events are turned off natively.
I'm splitting this PR only to include Material UI and created an issue for Joy UI: #38959. I added the explanation in this PR's description, but TL;DR is that Joy UI's change is more complex. It's worth it to improve Material UI's buttons separately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we are capturing all scenarios based on manual testing, but we likely want to add some tests around this, as it's easy to break it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DiegoAndai I see you tried to push the solution above and beyond, covering more cases than I thought of initially, greedy 😁. There are limits though, I doubt we will be able to cover everything. Hopefully, there are workaround, otherwise, we could fallback a bit to cover fewer but still meaningful cases.
'&:active': { | ||
userSelect: 'none', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we ever need this?
I can think of 3 types of elements we can render:
<a>
solved by built-in behavior.<button>
solved by built-in behavior.- regular element, e.g.
<div>
. Do we want to optimize for devs that do YOLO? I would expect always 1 and 2.
'&:active': { | |
userSelect: 'none', | |
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will need this in Firefox to have the same behavior, as buttons in Firefox are not selectable by dragging from outside. We could add it inside the ownerState.component === 'button'
condition, so it only applies to buttons, but I don't see the harm of supporting regular elements as well. What do you think?
Hey @oliviertassinari, I finally got time to update this PR and reply to your feedback. It is ready for you to review again 😊 I decreased the scope. I think you're right: "cover fewer but still meaningful cases" |
PR got out of date as it has been on hold for a while. Closing as stale. We'll have to revisit this later this year while working on v7. |
Following up on Point 13 of this comment: #36622 (comment).
Edited Sept. 13:
The original intent of this PR was to enhance the button's text selection for both Material UI and Joy UI. I'm changing that to include only Material UI.
Joy UI's change is more complex as the disabled styles are implemented in
variantUtils.tsx
and not directly in the components. That change could impact other components, so I prefer someone with more experience in the Joy UI codebase to own it. I created an issue for it: #38959Material UI button's text selection
Preview: https://deploy-preview-38158--material-ui.netlify.app/material-ui/react-button/
The expected behavior is:
A technical limitation (explained in detail here) makes it difficult to achieve this when the DOM element used is not
button
and it's disabled. The best solution is implementing the behavior we want for all variations except for disabled non-button
elements. This PR enables all selection for those elements, which is better than no selection, IMO.You can check out the differences in this comparison experiment.
Components changed
ButtonBase
, which impacts various components likeFAB
,Button
, andCardActionArea
Chip
(clickable)Link
material-next
'sButtonBase
Note 1
The origin of the
user-select: none
rule is this commit, which was fixing issue #8 (it goes baaaack). The issue does not come back with this PR.Note 2
Chrome's and Safari's default behavior for buttons is that text is selectable. In Firefox, the buttons' text is not selectable.