WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.39k stars 4.15k forks source link

Update the `Button` component #63856

Open jameskoster opened 2 months ago

jameskoster commented 2 months ago

Buttons are a ubiquitous element in most apps, a solid design can help elevate the polish of the overall UI.

Here's a matrix of the current variants / states of the Button component.

Buttons

Issues

Let's refine the list of issues before exploring potential solutions. Do you agree with this list? Are any items missing?

Task list

Based on the discussion in this issue, here's a list of items to be implemented. Refer to this codepen for demonstrations.

joedolson commented 2 months ago

I note that 'Focus' is excluded from this array of styles; is that because it's primarily added outside the button, via outlines, or for some other reason? I feel like it should be included for completeness.

jameskoster commented 2 months ago

You're right, they should be included. I'll update the diagram :)

annezazu commented 2 months ago

Just a quick note that I'd love to see a more descriptive title for this issue.

jameskoster commented 2 months ago

Something like this shimmer effect (codepen) could be fun to try for the busy state:

cbirdsong commented 2 months ago

This issue seems like it would be relevant to any button redesign:

The ability to include icons alongside text labels would be a win for usability.

seifeldinio commented 2 months ago

I've updated the matrix of button variants to ensure consistency, here's the design for it:

updated

Additionally, consolidating the default button state with the tertiary variant could help streamline the design and reduce complexity. You can see the updated design here:

updated-2

For the busy state design, while the shimmer effect might be engaging, it could present accessibility concerns for users sensitive to flashing elements.

Here’s a CodePen example featuring a simpler loader that might be a safer choice: Codepen

You can also view a demo of this loader here:

https://github.com/user-attachments/assets/9ba6720c-3fb7-4af2-a61c-4bc60f0d2dd4

Looking forward to your feedback!

joedolson commented 2 months ago

I agree that the shimmer effect could be problematic; although as long as it respects prefers-reduced-motion flags, it's not a major concern.

This panel of designs is still missing focus states, however. Those should be included.

jameskoster commented 2 months ago

Thanks for sharing @seifeldinio :)

I'd be interested to get feedback from @WordPress/gutenberg-components on the idea of using a spinner for the busy state. We'd need to ensure the button retains it's width which might add some complexity? Ideally the visuals would match the native Spinner component too.

For the disabled states it would be good to avoid opacity; that method won't work as well as solid colors for different color schemes (https://github.com/WordPress/gutenberg/issues/53612). Additionally I'd say the disabled primary/destructive buttons are commanding too much attention. Let's explore some more options there.

Finally, a consistent focus treatment could be worth exploring, for example always using an outset focus ring:

focus

This convention can be applied consistently across all components, and in this case ensure the same footprint for all button types.

ciampo commented 2 months ago

using a spinner for the busy state. We'd need to ensure the button retains it's width which might add some complexity? Ideally the visuals would match the native Spinner component too.

It shouldn't be problematic if we basically overlay and center a spinner on top of the existing button. Do you have some mockups to share?

tyxla commented 2 months ago

FWIW it used to be a common practice to have spinners inside buttons in Bootstrap:

https://getbootstrap.com/docs/4.4/components/spinners/#buttons

jameskoster commented 2 months ago

As with most interactive elements it's not easy to judge the design by working with static files, so I've started exploring Buttons on codepen (please excuse the spaghetti code).

buttons

Some notes on the designs that it would be good to discuss:

Additionally guidelines should be written around when each variant should be used, do's/don't's, etc.

crisbusquets commented 2 months ago

Thanks for working on this, @jameskoster !

I added a background to the secondary hover & active states. Without it the hover effect is virtually invisible. Tbh, I like it. Another option could be to make the border thicker on hover:

https://github.com/user-attachments/assets/aa48a5df-ef78-46e4-a339-0730c78b785f

Focus ring always blue, this is a departure from the current design where the focus ring takes on the accent color of the button. IE destructive buttons have a red focus ring. I don't see much value in this, and the consistent focus ring simplifies things a bit.

To me it feels weird that the focus ring is blue when the button is destructive. But that's maybe a personal preference.

Disabled states have a transparent overlay which applies a grayscale filter.

This gray treatment will help a lot when combining primary and secondary CTAs and the primary is disabled for some reason. Thanks for working on it!

Spinner for busy state, as discussed above. Click a button to view it.

Love it!

jameskoster commented 2 months ago

To me it feels weird that the focus ring is blue when the button is destructive.

It did to me as well until I looked around and saw that very few design systems seem to colorise the focus ring, either for destructive buttons, errored inputs, or anything really. That doesn't mean we shouldn't, but it seems a good moment to question it. Perhaps there are some a11y best practises to guide this one way or the other... cc @joedolson.

joedolson commented 2 months ago

The purpose of the focus ring is to draw attention quickly, so that a user can quickly and efficiently locate where they are focused. While I'm not aware of any standards governing whether it should be colorized or not, in my opinion consistency is going to be a big part of making it easy to find - and if it changes color depending on the state of type of control, it's going to be harder for a user to spot.

In my opinion the focus ring should only represent one thing: focus. It doesn't need to also represent the state or type of control; the control design should be doing that job.

jameskoster commented 2 months ago

Font-weight: 500 is applied to visually distinguish tertiary buttons from regular text, which otherwise share identical styling.

I discussed this with some designers yesterday and have reverted back to font-weight: 400. The main reason being that the increased weight harms legibility in some languages. For the a11y question around this subject, we should ensure the component guidelines strongly discourage tertiary button variants appearing in scenarios that they could be confused with body text. There may even be very strict situations in which this variant is permitted.

mirka commented 1 month ago
  • Contentious: cursor: default on resting state. Some more context here, which essentially boils down to "only links should use the pointer cursor". I think there's a nuance here, since there are several examples of buttons in the site editor that change the URL on click. Let's discuss.

As for this point, I'm leaning towards sticking with the current de facto style logic in our UIs, which is to use cursor: pointer on all interactive elements. Although the traditional guidance is to use it only for text links to make up for the lower affordance, by now so many of us have grown to expect pointer cursors on all interactive elements in web apps.

I also think it will be much easier for us to maintain consistency across the app, just because that rule is much more simpler than having to assess from an affordance perspective whether each element needs cursor: pointer or not.

jameskoster commented 1 month ago

Yup, I'm on the fence about that one, so very happy to defer for now.


One other piece of feedback I've seen is that the secondary button style is too strong. A contrast preference would remedy that byconditionally reducing the strength of the stroke, but I wanted to open the door to any other potential ideas.

There are a few options we might consider like;

I'll create some mockups when I get a second.

jameskoster commented 1 month ago

Here are a couple of alternative options for the secondary variant:

buttons

The top two are variations on a theme; the bottom border provides contrast and a subtle gradient helps distinguish from text inputs.

Bottom-left tries a much subtler background color and no stroke. Bottom-right tries a much subtler stroke color. In both cases font-weight is relied upon in order to indicate the element is interactive. There are drawbacks to this as outlined in https://github.com/WordPress/gutenberg/issues/63856#issuecomment-2265589757.

I'm not entirely sure any of these meet accessibility guidelines. Curious to hear any feedback.

ciampo commented 1 month ago
  • I added a background to the secondary hover & active states. Without it the hover effect is virtually invisible. I don’t love it, perhaps we should explore other options. A hover style is necessary imo to provide clear visual feedback.

Agreed that hover styles are necessary — and I also don't mind @crisbusquets 's exploration with thickening the border as an alternative to changing border color.

  • Contentious: cursor: default on resting state. [...] Let's discuss.

I agree with what Lena said above.

Agreed — we can apply whatever is decided in #63756

  • Font-weight: 500 is applied to visually distinguish tertiary buttons from regular text, which otherwise share identical styling. I'd appreciate a11y feedback on whether this is necessary or not.

I'd personally say that having visual cues to show what parts of the UI are interactive is necessary — whether that happens via font-weight or in other ways, I don't think it matters as much

  • Disabled states have a transparent overlay which applies a grayscale filter.

To be future-proof, let's also consider theming in mind: ie. what if the button's main color is fully desaturated? Applying a gray scale filter in that case would not cause any visual differences.

The obvious choice is also also apply reduced opacity on the button's contents (but not the focus ring), but I'd be open to other alternatives.

  • Focus ring always blue, this is a departure from the current design where the focus ring takes on the accent color of the button. IE destructive buttons have a red focus ring. I don't see much value in this, and the consistent focus ring simplifies things a bit.
  • Focus ring is applied consistently across all variants.
  • Focus ring applied to focus-visible so that it only appears when a user interacts with the button via keystroke. I'd welcome a11y feedback on this point too.
  • Focus ring is slightly lighter, but still meets contrast requirements.

Agreed on the focus ring changes — and also agree on applying a consistent focus ring color as suggested by Joe above

  • Spinner for busy state, as discussed above. Click a button to view it.

Looks good

  • Added a dedicated prop for full-width buttons. This treatment is used quite often, but applied using overrides which isn't ideal.

Style overrides per se are ok if applied on “outer” styles (positioning, flex child properties, sizing to a certain extent).

We discourage style overrides when:

In that sense, if the only thing that changes for "full-width" buttons is their external width, it should be totally fine for a consumer of the Button component to apply that via CSS.

  • Consolidated tertiary and default variants.

Does that mean that, by default, a button without a specified variant would render with "tertiary" styles? Given that we may discourage using tertiary buttons in certain scenarios for their lack of visual interactivity hints, would it be a good choice to default to tertiary?

One other piece of feedback I've seen is that the secondary button style is too strong

I didn't perceive the secondary button style as "too strong" — to me it feels like a good balance between the primary (which is definitely "strong") and tertiary (which is very subtle).

Here are a couple of alternative options for the secondary variant:

The gradients to me feel foreign to Gutenberg's style. Of those 4 alternatives, I prefer bottom left and bottom right — although I agree that bottom left would be hard to pull off consistently when adding theming in the mix.

jameskoster commented 1 month ago

I also don't mind @crisbusquets 's exploration with thickening the border as an alternative to changing border color.

I'll try it in the codepen :)

Applying a gray scale filter in that case would not cause any visual differences.

To clarify, there are two combined effects. One is a semi-transparent overlay, the other is a grayscale filter. So if the theme uses grey for the primary color, disabled buttons would still appear lighter.

Does that mean that, by default, a button without a specified variant would render with "tertiary" styles? Given that we may discourage using tertiary buttons in certain scenarios for their lack of visual interactivity hints, would it be a good choice to default to tertiary?

Good questions. A cursory glance at other design systems reveals that generally our 'secondary' style is the more common default. That makes sense given the quirks around the borderless tertiary variant that you pointed out. However, wouldn't making secondary the default cause backwards compatibility issues?

Ultimately I feel the guidelines should provide clear instructions about when to use each variant, and the default should effectively be irrelevant. This would include instructions to not use the tertiary variant in situations where it might easily be confused for body text.

jameskoster commented 1 month ago

I updated the codepen. The secondary variant now features a .5px thicker stroke on hover as suggested. In practise, I'm not a huge fan. I don't love how the stroke feels heavier than the text.

I also added the alternative approaches to the secondary variant, and some example button groupings:

Screenshot 2024-08-15 at 16 27 40

For me both of the alternatives feel a bit more balanced next to the primary variant. I have a slight preference for the version with the lighter stroke. Keen to hear feedback!

ciampo commented 1 month ago

Personally, no strong preference here — I think that all 3 options for the "secondary" variant could work.

As I said earlier, the only challenge I see with the third option (ie. no border, light background color) is that it may not always work well depending on the choice of primary color (something to keep in mind when enabling theming).

cbirdsong commented 1 month ago

The gradients to me feel foreign to Gutenberg's style.

Gradients may be out of vogue with many modern design styles, but they are very useful for conveying what's interactive and what isn't. I would welcome a move back in that direction.

jameskoster commented 1 month ago

As I said earlier, the only challenge I see with the third option (ie. no border, light background color) is that it may not always work well depending on the choice of primary color

Could you expand on that? In which situations would it not work well?

ciampo commented 1 month ago

The gradients to me feel foreign to Gutenberg's style.

Gradients may be out of vogue with many modern design styles, but they are very useful for conveying what's interactive and what isn't. I would welcome a move back in that direction.

@cbirdsong Absolutely! What I was trying to say, is that currently I don't see gradients being used in Gutenberg design language.

As I said earlier, the only challenge I see with the third option (ie. no border, light background color) is that it may not always work well depending on the choice of primary color

Could you expand on that? In which situations would it not work well?

@jameskoster I'm mostly thinking about theming. Let's take this secondary button design proposal into account:

Screenshot 2024-08-16 at 11 28 42

In terms of colors:

But if we allow for theming, users could specify any primary color. And when that happens, we're not guaranteed that those same tweaks that worked well for our default primary color will also result in a pleasant/accessible design for the new custom primary color passed via theming.

Of course, the same could happen with a white background, if the primary color doesn't have enough contrast against white anyway. And I also realize this is definitely an aspect that will affect theming in a broader sense (ie. do we allow users to define any color as the primary theme color? how do we calculate internally all the variations of the primary color? how do we make sure we can still retain the changes in lightness / saturation and ensure enough contrast? etc).

In short, my feedback is not blocking for the Button component per se, but more a reflection on the potential challenges that theming brings and could affect Button

jameskoster commented 1 month ago

Got it. The work Saxon was doing around the theme component / color scales should actually ensure this works, pretty much regardless of the spot color from which the palette is generated.

jasmussen commented 1 month ago

Thanks for adding consistency. From the visual changes to the base resting states, it's not clear a design has been found that improves upon them from what they are today (referring to color changes, shadows, gradients). This is especially important to consider in context of the fuller interface, such as seeing it inside an inspector and a modal, to ensure belonging.

jameskoster commented 1 month ago

Personally I find this version to be an improvement:

Screenshot 2024-08-22 at 11 31 17

Not necessarily the button styling in isolation, but in the context of the wider interface I find there to be a pervasive issue of noise and contrast. There are a lot of strong colors and outlines that make certain UIs feel overwhelming. This relates to the conversation we've had around ToggleGroupControl recently.

As an example here's a comparison from the Block Inspector:

Current Proposed
Screenshot 2024-08-22 at 11 38 02 Screenshot 2024-08-22 at 11 37 46

Currently the button has very similar styling and weight to the inputs it often appears adjacent to. If you squint it's kind of hard to tell them apart. This would be more pronounced for folks with certain visual impairments.

Additionally the proposed design forms a base from which it's easier to create hover / active styles, a detail that has proven tricky to get right with the current implementation.


All that said, changing the secondary button styling is probably a detail to explore separately, I wouldn't want it to get in the way of the other enhancements here. I've updated the task list in the OP to capture the points around which there seem to be consensus.

jasmussen commented 1 month ago

All that said, changing the secondary button styling is probably a detail to explore separately, I wouldn't want it to get in the way of the other enhancements here. I've updated the task list in the OP to capture the points around which there seem to be consensus.

Perhaps that's the best approach? Extracting this and proposing it in isolation with a broad ping?