Open jameskoster opened 3 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.
You're right, they should be included. I'll update the diagram :)
Just a quick note that I'd love to see a more descriptive title for this issue.
Something like this shimmer effect (codepen) could be fun to try for the busy state:
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.
I've updated the matrix of button variants to ensure consistency, here's the design for it:
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:
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!
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.
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:
This convention can be applied consistently across all components, and in this case ensure the same footprint for all button types.
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?
FWIW it used to be a common practice to have spinners inside buttons in Bootstrap:
https://getbootstrap.com/docs/4.4/components/spinners/#buttons
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).
Some notes on the designs that it would be good to discuss:
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.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: https://github.com/WordPress/gutenberg/issues/63756Font-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. 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.tertiary
and default
variants. Additionally guidelines should be written around when each variant should be used, do's/don't's, etc.
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!
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.
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.
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.
- Contentious:
cursor: default
on resting state. Some more context here, which essentially boils down to "only links should use thepointer
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.
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.
Here are a couple of alternative options for the secondary
variant:
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.
- 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.
Cursor: not-allowed
on disabled states, there's a dedicated issue to discuss this here: Find consensus around usingcursor: not-allowed
on disabled elements and apply across #63756
Agreed — we can apply whatever is decided in #63756
Font-weight: 500
is applied to visually distinguishtertiary
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:
.components-button
, for example) to apply styles — those classnames are private implementation details and should not be used outside of the components package;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
anddefault
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.
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.
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:
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!
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).
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.
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?
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:
In terms of colors:
#3858e9
) as the text color;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
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.
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.
Personally I find this version to be an improvement:
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 |
---|---|
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.
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?
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.Issues
isPressed
doesn’t seem to have much use outside thedefault
variant. It indicates whether a button is toggled on or not, e.g. “Bold” in the block toolbar.tertiary
variant?primary
variant are very prominent, and draw a lot of attention given their un-interactivity.secondary
andtertiary
variants) it’s not obvious that the element is a button when it appears in close proximity to body text.:focus
meaning they appear on click. We might consider moving those styles to:focus-visible
so they appear on keyboard interaction instead.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.
default
withtertiary
focus-visible