Skip to content
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

Update the Button component #63856

Open
8 tasks
Tracked by #53322
jameskoster opened this issue Jul 23, 2024 · 29 comments
Open
8 tasks
Tracked by #53322

Update the Button component #63856

jameskoster opened this issue Jul 23, 2024 · 29 comments
Labels
Design System Issues related to the system of combining components according to best practices. Needs Accessibility Feedback Need input from accessibility Needs Design Feedback Needs general design feedback. Needs Design Needs design efforts. [Package] Components /packages/components

Comments

@jameskoster
Copy link
Contributor

jameskoster commented Jul 23, 2024

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

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

Buttons

Issues

  • Hover styles are inconsistent, some variants don't have them at all.
    • Sometimes the focus ring matches the hover accent, other times it does not.
  • Active states for admin-colored variants (secondary, tertiary) use gray text. This looks particularly awkward on an admin-colored surface (see Tertiary:active).
  • Busy states look a bit dated, and do not work well on the link variant.
  • It’s not clear when to use the ‘default’ variant, or how that fits in with the others.
    • isPressed doesn’t seem to have much use outside the default variant. It indicates whether a button is toggled on or not, e.g. “Bold” in the block toolbar.
    • Should this be a separate component, or could it be consolidated with the tertiary variant?
  • Disabled states of the primary variant are very prominent, and draw a lot of attention given their un-interactivity.
  • Font weight matches regular text. This isn't a problem when the button has a solid background as the user can easily identify the element as a button. But when it doesn’t (secondary and tertiary variants) it’s not obvious that the element is a button when it appears in close proximity to body text.
  • Inconsistent focus styles – on primary buttons there's a small gap between the button and the focus ring, this is absent in other variants.
  • Some focus rings are semi-opaque (Button: Improve the aria-disabled focus style #62480)
  • Focus styles are applied to :focus meaning they appear on click. We might consider moving those styles to :focus-visible so they appear on keyboard interaction instead.
    • Hover + focus styles are incompatible for some variants. e.g. Hovering a focussed secondary button removes the focus ring.

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.

  • Update busy state design to utilise a spinner
  • Consolidate default with tertiary
  • Add hover states to variants that are missing them
  • Align focus ring styling across all variants & fix existing issues
  • Apply focus styles to focus-visible
  • Consistent disabled state styling
  • Do not colorise focus rings for destructive buttons
  • Update secondary button appearance #64744
@jameskoster jameskoster added Needs Design Feedback Needs general design feedback. Needs Design Needs design efforts. [Package] Components /packages/components labels Jul 23, 2024
@joedolson joedolson added the Needs Accessibility Feedback Need input from accessibility label Jul 23, 2024
@joedolson
Copy link
Contributor

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
Copy link
Contributor Author

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

@annezazu
Copy link
Contributor

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

@jameskoster jameskoster changed the title Buttons Update the Button component Jul 23, 2024
@jameskoster
Copy link
Contributor Author

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

@cbirdsong
Copy link

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
Copy link

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:

demo.mp4

Looking forward to your feedback!

@joedolson
Copy link
Contributor

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
Copy link
Contributor Author

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 (#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
Copy link
Contributor

ciampo commented Jul 31, 2024

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
Copy link
Member

tyxla commented Jul 31, 2024

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
Copy link
Contributor Author

jameskoster commented Aug 1, 2024

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:

  • 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.
  • 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.
  • Cursor: not-allowed on disabled states, there's a dedicated issue to discuss this here: Find consensus around using cursor: not-allowed on disabled elements and apply across #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.
  • Disabled states have a transparent overlay which applies a grayscale filter.
  • 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.
  • Spinner for busy state, as discussed above. Click a button to view it.
  • Added a dedicated prop for full-width buttons. This treatment is used quite often, but applied using overrides which isn't ideal.
  • Consolidated tertiary and default variants.

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

@crisbusquets
Copy link
Contributor

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:

border-cta.mp4

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
Copy link
Contributor Author

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
Copy link
Contributor

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
Copy link
Contributor Author

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
Copy link
Member

mirka commented Aug 12, 2024

  • 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
Copy link
Contributor Author

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;

  • Omitting the border in favor of a solid background (though any background must have a 3:1 contrast ratio against the surrounding UI, and the text must have a contrast ratio of 4.5:1 against the button background).
  • A more subtle stroke treatment.
  • Revisit the font-weight discussion... with increased weight I believe the weight alone would provide adequate contrast and we could use a lighter stroke.

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

@jameskoster
Copy link
Contributor Author

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 #63856 (comment).

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

@ciampo
Copy link
Contributor

ciampo commented Aug 15, 2024

  • 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:

  • consumers use internal classnames (ie. .components-button, for example) to apply styles — those classnames are private implementation details and should not be used outside of the components package;
  • consumers override "inner" styles (as opposed to the "outer" styles described above), causing risk of breaking in the long run

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
Copy link
Contributor Author

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
Copy link
Contributor Author

jameskoster commented Aug 15, 2024

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
Copy link
Contributor

ciampo commented Aug 15, 2024

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
Copy link

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
Copy link
Contributor Author

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
Copy link
Contributor

ciampo commented Aug 16, 2024

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:

  • we'd likely use our default primary color (#3858e9) as the text color;
  • for the button's background color, we would apply some transformations to that primary color (keep the same hue, make it lighter, potentially a bit desaturated). When doing that, we can tweak the exact amount for those transformations to make sure we reach the right balance, so that the different button background is noticeable, but offers enough contrast with the button text

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
Copy link
Contributor Author

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
Copy link
Contributor

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
Copy link
Contributor Author

jameskoster commented Aug 22, 2024

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
Copy link
Contributor

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?

@jasmussen jasmussen added the Design System Issues related to the system of combining components according to best practices. label Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design System Issues related to the system of combining components according to best practices. Needs Accessibility Feedback Need input from accessibility Needs Design Feedback Needs general design feedback. Needs Design Needs design efforts. [Package] Components /packages/components
Projects
Status: Next
Status: 🧊 Icebox
Development

No branches or pull requests

10 participants