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

Add button interactive states in the stylebook #67541

Open
wants to merge 2 commits into
base: trunk
Choose a base branch
from

Conversation

matiasbenedetto
Copy link
Contributor

@matiasbenedetto matiasbenedetto commented Dec 3, 2024

What?

Add button interactive states in the stylebook

Why?

To showcase the different interactive states of the button in the stylebook.
This is part of the effort around adding a UI to define the styles of those interactive states: #38277
Fixes: #67542

How?

Bu adding one button for each interactive state in the stylebook.

Testing Instructions

  1. Checkout this PR.
  2. Add some styles for the interactive states of the button elements in your theme.json file. Example:
"styles":{
		"elements": {
			"button":{
				
				"color": {
					"background": "yellow",
					"text": "blue"
				},
				":hover": {
					"color": {
						"background": "orange",
						"text": "red"

					}
				},
				":visited": {
					"color": {
						"background": "green",
						"text": "blue"
					}
				},
				":active": {
					"color": {
						"background": "red",
						"text": "yellow"
					}
				},
				":focus": {
					"color": {
						"background": "blue",
						"text": "green"
					}
				},
				":any-link": {
					"color": {
						"background": "purple",
						"text": "white"
					}
				},
				":link": {
					"color": {
						"background": "pink",
						"text": "black"
					}
				}
			}
		}
	},
  1. Browse the stylebook and got to the 'design' tab.
  2. Check that the styles defined in theme.json are observable in the button

Maybe it's simpler for you to download and try this theme featuring only the button interactive states as in the screenshot:
testing-button-states.zip

Screenshots or screencast

Before After
image image

Copy link

github-actions bot commented Dec 3, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: matiasbenedetto <[email protected]>
Co-authored-by: youknowriad <[email protected]>
Co-authored-by: jasmussen <[email protected]>
Co-authored-by: ramonjd <[email protected]>
Co-authored-by: tellthemachines <[email protected]>
Co-authored-by: jameskoster <[email protected]>
Co-authored-by: MaggieCabrera <[email protected]>
Co-authored-by: luminuu <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@matiasbenedetto matiasbenedetto added [Type] Enhancement A suggestion for improvement. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Feature] Style Book labels Dec 3, 2024
Copy link

github-actions bot commented Dec 3, 2024

Flaky tests detected in 7869490.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/12148020769
📝 Reported issues:

@jasmussen
Copy link
Contributor

Nice, thanks for working on this.

Noting that this PR will substantially benefit from #67546, which makes the sections for each category much clearer, so it might be worth a rebase once it lands.

I understand this focuses on the Button first, that's sensible, we can look at states for navigation items and other blocks at a later time. Here's what I see, scrolling down in the Style Book:

Screenshot 2024-12-04 at 11 15 25

This PR is closely related to the work that happens in #53431 as well, insofar as the new categories that are being discussed, and even moving the style book into the Site View of the site editor, here:

2024-12-04 11 22 46 localhost 83bdfe79d67e

That latter piece is important mainly because those categories will need to be invoked from navigation on the left. To that end, I realized that those categories could maybe need a little more clarification, which I'll share on #53431 in a bit. The relevant part is this one:

button block

You'd get to that both in Global Styles > Blocks > Button. It would be something similar for Navigation, sketched here:

essentially

So what do we need for this PR to land? Not all of that, to be clear, but perhaps:

Additionally, we should find some kinder labels than :active, :hover, etc.

  • default → Button
  • :active → Button (Active)
  • :focus → Button (Focus)
  • :hover → Button (Hover)
  • :visited → Button (Visited)

Are :link and :any-link supported at the moment? It's not clear to me whether we should surface those here, honestly. CC: @WordPress/gutenberg-design

@jasmussen
Copy link
Contributor

Shared an update here: #53431 (comment), not necessarily needed for this PR to land, but good broader context, hopefully.

@matiasbenedetto
Copy link
Contributor Author

matiasbenedetto commented Dec 4, 2024

Are :link and :any-link supported at the moment?

Yep, they are supported. Reference from theme.json schema: https://github.com/WordPress/gutenberg/blob/trunk/schemas/json/theme.json#L1704-L1736

@matiasbenedetto
Copy link
Contributor Author

Additionally, we should find some kinder labels than :active, :hover, etc.
default → Button
:active → Button (Active)
:focus → Button (Focus)
:hover → Button (Hover)
:visited → Button (Visited)

Done in the last commit.

image

const [ elementsButton ] = useGlobalStyle( 'elements.button' );
const blocks = BUTTON_STATES.map( ( { key } ) => {
const styles =
( key !== 'default' ? elementsButton[ key ] : elementsButton ) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when we have both a "default" and a "state", are we merging the state styles with the "default" styles (I just want to confirm that this is covered because it's not clear by reading this code)

.edit-site-style-book__example-subtitle {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-size: 9px;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is very weird that we're rendering the titles and subtitles... within an iframe. Do we have any context on this decision? I think it would have been a lot simpler to avoid an iframe for style book and only use iframes for the examples (maybe even use BlockPreview rather than BlockList and Provider)

For clarity, I'm not asking of any change in this particular PR but I wonder if this was considered and if we didn't, we should probably consider as part of our efforts to improve style book. cc @tellthemachines @ramonjd @aaronrobertshaw

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking of the font size, it's a bit small. The later mockups have two heading sizes: the main category (16px), and the subheading size (13px):
Screenshot 2024-12-05 at 10 58 41

Potentially this can be separate since there's a lot of separate work going on with headings, but there's a spec here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any context on this decision? I think it would have been a lot simpler to avoid an iframe for style book and only use iframes for the examples

It's an abstraction of noisysock's original implementation.

🤔 If I recall correctly, at the time it was to simulate an "editor instance" within the editor, but isolated so as to have more control over window resizing, styles and so on. It proved useful for revisions where discrete global styles configs could be loaded into the iframe without affecting the main canvas.

As is with many features, things just grew from there.

I think it would have been a lot simpler to avoid an iframe for style book and only use iframes for the examples (maybe even use BlockPreview rather than BlockList and Provider)
I wonder if this was considered and if we didn't, we should probably consider as part of our efforts to improve style book

I agree the setup is ripe for refactoring.

I tried a few variations while researching for #62216. I think it's worth reigniting, so maybe that issue could be extended/repurposed.

It will be a whole lot simpler if Global styles (including revisions and style book) finds a new home in the left-hand "view" site editor side bar.

There have been noises to that effect, but I doubt it will happen soon.

By "simpler" I mean that the component wouldn't have to live in the editor canvas and do all the iframe/slot faffery.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "simpler" I mean that the component wouldn't have to live in the editor canvas and do all the iframe/slot faffery.

I feel like refactoring the stylebook to use multiple small "Block Previews" rather than a huge iFrame for everything is independent from whether it should be using the EditorContentSlotFill or not.

Copy link
Contributor

@tellthemachines tellthemachines Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From memory the main reason we went with a single iframe for everything was in order to correctly show the theme background, whether it's a plain color or a background image. It's particularly relevant for background images as it means the image won't be split up and contained inside multiple small frames, but will replicate what it looks like on the actual site:

Screenshot 2024-12-06 at 10 14 16 am

We'd have the same problem with gradient backgrounds too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's a good reason :) I wonder if we can have a background iframe positioned absolutely behind everything. (Anyway, I guess we can probably move this discussion to a separate thread/issue :p )

@youknowriad
Copy link
Contributor

youknowriad commented Dec 5, 2024

The subtitles look a bit weird to me (too small and missing some padding bottom maybe)

Screenshot 2024-12-05 at 10 37 13 AM

@jasmussen
Copy link
Contributor

Re: the subtitles, left a comment here: #67541 (comment)

@jasmussen
Copy link
Contributor

I'm really waffling on surfacing "Any link" and "Link" here. For a button, it's not clear these are useful to style: for example if I wrote custom CSS I'd never use them. By surfacing them here, we give them prominence, perhaps suggesting you should be styling them.

Would it be possible to hide these to start, and then surface them, perhaps under a "More..." link at a later time, if we get feedback these are needed? CC: @WordPress/gutenberg-design for any additional thoughts.

@tellthemachines
Copy link
Contributor

Would it be possible to hide these to start, and then surface them, perhaps under a "More..." link at a later time, if we get feedback these are needed? CC: @WordPress/gutenberg-design for any additional thoughts.

Is it necessary to to show states that aren't styled by the theme? Looking at TT5 and TT4, they take up a lot of space and don't add much value:

Screenshot 2024-12-06 at 10 28 25 am Screenshot 2024-12-06 at 10 26 03 am

If we showed only states that are explicitly styled, I suspect we'd get hover and focus most of the time. visited is a popular one for links, but not so much for buttons.

Copy link
Contributor

@tellthemachines tellthemachines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I'm noticing when testing this on actual themes is that quite a few of them don't provide hover and focus states for buttons 😅

It's common practice to provide hover styles for links, but maybe not so much for buttons. It's also common practice (and considered by some folks best practice for a11y reasons) to rely on browser defaults for focus styles.

Another thing to consider is that themes that do provide focus styles might do so for all focusable elements, or at least provide baseline styles and then customise for individual elements.

TT5 provides base outline styles in its stylesheet, whereas TT4 does it in the custom CSS in theme.json. These are styles that we're not picking up here, and I can't think of a straightforward way of doing so unless we get computed properties for the actual elements in the DOM.

Copy link
Member

@ramonjd ramonjd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. I think it's good to display the button states.

It would be nice to see the pseudo states editable in the UI, similar to the link element. Is that part of #38277?

const BUTTON_STATES = [
{
key: 'default',
title: __( 'Button' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's block title of "Button" do you think these labels could just describe the state? E.g., 'Default', 'Active', 'Hover' etc

Screenshot 2024-12-06 at 1 38 00 pm

( key !== 'default' ? elementsButton[ key ] : elementsButton ) ||
{};
return createBlock( 'core/button', {
text: __( 'Call to Action' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better than the above still, instead of call to action, make the button text the state. The downside is that the buttons' widths will vary, but the CSS could be tweaked a bit e.g.,

Screenshot 2024-12-06 at 1 48 09 pm

Anyway, just an idea.

@@ -239,6 +239,11 @@ export const STYLE_BOOK_IFRAME_STYLES = `
text-transform: uppercase;
}

.edit-site-style-book__example-subtitle {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make the button text describe its state we wouldn't need this CSS anyway.

@ramonjd
Copy link
Member

ramonjd commented Dec 6, 2024

One thing I'm noticing when testing this on actual themes is that quite a few of them don't provide hover and focus states for buttons

That's a very good point!

Would the button state previews be more useful if there were controls in global styles to modify these states first?

TT5 provides base outline styles in its stylesheet, whereas TT4 does it in the custom CSS in theme.json. These are styles that we're not picking up her

Ah yes true. I think custom theme.json CSS is rendered inside the style book iframe, but in the case of TT4 there's no .wp-site-blocks class to select the elements 🤔

It would be nice to be able to "force" the :hover etc state on the element so they pick up any inherited CSS as well, but I'm not sure there's a reliable way to do that.

@jasmussen
Copy link
Contributor

Is it necessary to to show states that aren't styled by the theme?

and

One thing I'm noticing when testing this on actual themes is that quite a few of them don't provide hover and focus states for buttons

These are related.

One of the best reasons for surfacing these pseudo states is to allow you easy access to add them. It's very much a block developer tool, you use these states when you build the theme. And so showing them unstyled can serve as a reminder: hey, you forgot a focus style.

Of course the buttons should be shown in that state. In the case of Twenty Twenty-Five, it actually does provide its own focus style across both links and buttons. But it does so using custom CSS, but mainly because these states were not editable in the editor at the time of shipping the feature. So in a way, the fact that these aren't styled by the theme, is part of the reason we do work. It's impactful, thank you!

I still don't think we should show :link and :any-link though, I think it's fine that if you want to style those, you have to edit theme.json.

visited is a popular one for links, but not so much for buttons.

That's another good point, and an argument to also hide this one, require you to edit theme.json for providing this too.

As far as things looking duplicated here, this is intentional. It is to imply: this is the same button, or navigation item, we're just showing differente states of the same item:

Screenshot 2024-12-06 at 09 05 07

Screenshot 2024-12-06 at 09 05 11

This can be polished further, to be sure. But I wouldn't let that block this PR. Getting the behavior right and looking like the mockups, should be the first step, and enough to merge.

@jameskoster
Copy link
Contributor

I still don't think we should show :link and :any-link though, I think it's fine that if you want to style those, you have to edit theme.json.

Maybe they should be hidden by default, but appear when the style exists in theme.json? If I built a theme that included styles for these states, I think I'd expect them to be included in Style Book.

@youknowriad
Copy link
Contributor

Maybe they should be hidden by default, but appear when the style exists in theme.json? If I built a theme that included styles for these states, I think I'd expect them to be included in Style Book.

The problem with them being default is for later, when we allow editing these things, it gives an indication to the user that he can edit these things separately (maybe even click on them to select the state)

@matiasbenedetto
Copy link
Contributor Author

matiasbenedetto commented Dec 6, 2024

Maybe they should be hidden by default, but appear when the style exists in theme.json?

From my point of view, the Stylebook is a guide to all the site elements that can be styled/customized. Not all sites use all the heading levels, and we still don't hide them in the Stylebook. Listing all the possible interactive states of an element makes it easy to select, preview, and style, which seems to be one of the main goals and utility of the Stylebook.

It would be nice to see the pseudo states editable in the UI, similar to the #41976. Is that part of #38277?

Yes, this is part of an effort to add the editing UI for the interactive states. I was planning to work on that after we ship this.

const styles =
( key !== 'default' ? elementsButton[ key ] : elementsButton ) ||
{};
return createBlock( 'core/button', {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to keep in mind: the block might be deregistered and could trigger errors.

See:

@tellthemachines
Copy link
Contributor

One of the best reasons for surfacing these pseudo states is to allow you easy access to add them. It's very much a block developer tool, you use these states when you build the theme. And so showing them unstyled can serve as a reminder: hey, you forgot a focus style.

This makes sense for hover, but with focus many themes rely on browser defaults, which is also a correct thing to do, and in those cases this button will never show the actual focus styles.

That's not terrible, but in the cases that themes do style focus they often (again, correctly) do it at a global level which we don't provide tools for and I don't believe we have plans to. We could potentially provide support for styling outline on all interactive elements at a global level, but outline is only one of a few popular ways to style focus. Themes will likely still leverage custom CSS or the theme stylesheet for more custom solutions, in which case the style book also won't show the actual focus styles.

Additionally, there's a risk of inadvertently worsening the accessibility experience for folks depending on focus styles if we allow editing those styles only on Buttons, or even if we allow editing them individually per block or element type. Focus styles should be consistent across all interactive elements on a website, which is why often they are styled all together.

I don't want to block this PR from landing, but we should be aware that the focus button state will in most cases not do its job of reflecting actual focus styles. We should also be very careful in the follow-ups with how we allow styling focus states in the UI, as there's a real risk of users inadvertently making their websites inaccessible by e.g. removing those styles altogether.

@MaggieCabrera
Copy link
Contributor

Is it necessary to to show states that aren't styled by the theme? Looking at TT5 and TT4, they take up a lot of space and don't add much value:

Then a theme like empty theme would not be able to add hover states, it would still force the theme creator to go into the theme files, which is what we are trying to avoid by providing a UI. Maybe we want to only allow a specific set of states for starters and then open up the discussion to show more, but I don't think we should rely on the theme styling them or not.

@MaggieCabrera
Copy link
Contributor

That's not terrible, but in the cases that themes do style focus they often (again, correctly) do it at a global level which we don't provide tools for and I don't believe we have plans to. We could potentially provide support for styling outline on all interactive elements at a global level, but outline is only one of a few popular ways to style focus. Themes will likely still leverage custom CSS or the theme stylesheet for more custom solutions, in which case the style book also won't show the actual focus styles.

We actually can change the outline, it's just theme.json only for the time being

@tellthemachines
Copy link
Contributor

We actually can change the outline, it's just theme.json only for the time being

Yeah but it's restricted to specific elements. There's no way of setting outline globally for all elements on focus. I reckon that's why both TT4 and TT5 use either custom CSS or the theme stylesheet to set a global style for all focusable elements. They also both use the outline property on the button element to set color and offset on the global outline.

@jasmussen
Copy link
Contributor

This makes sense for hover, but with focus many themes rely on browser defaults, which is also a correct thing to do, and in those cases this button will never show the actual focus styles.

Can we force the browser default style to appear in this state? The comparison in concpet is this, from the browser inspector tools:
Screenshot 2024-12-11 at 09 11 46

It doesn't seem possible, outside of literally replicating the user agent styles, of which these I found in Chrome:

a:-webkit-any-link:focus-visible {
    outline-offset: 1px;
}
:focus-visible {
    outline: -webkit-focus-ring-color auto 1px;
}

It might be possible to collect all the different browser-prefixed user agent focus styles, add them to one sheet, and catch all the major browsers, then simply apply that by default. But I have little confidence this would work as I'm outlining (though still seems worth trying, because in many themes, the default user styles are insufficient.)

An alternative, and this makes it even more important to not just show all the states (as we discussed for any-link and link). The first step of the PR could be surfacing those two, and focus, only if they are already provided in theme.json. But a longer term plan should ideally be in place, and this could be to use a similar patter to what the ToolsPanel does:

Screenshot 2024-12-11 at 09 19 39

That is, show an ellipsis, in its menu list all the states, and then allow you to check on the states that are not shown by default.

@tellthemachines
Copy link
Contributor

Can we force the browser default style to appear in this state?

We may be able to do this in a slightly hacky way 😅 Unfortunately getComputedStyle doesn't support pseudo-classes (though there's a proposal for that).

I guess we could trigger the focus state on the button programatically and then use getComputedStyle to get the outline and outline-offset properties, which are the most commonly used by browsers. That would also have the benefit of getting any generic outline styles the theme itself might have defined in its stylesheet.

@jasmussen
Copy link
Contributor

I guess we could trigger the focus state on the button programatically and then use getComputedStyle to get the outline and outline-offset properties, which are the most commonly used by browsers. That would also have the benefit of getting any generic outline styles the theme itself might have defined in its stylesheet.

That sounds interesting! Sounds like we could.

But per the discussion on link and any-link, perhaps we still start with the toolspanel approach, and put those two and focus behind that menu, and then we follow up separately by surfacing the focus style by default if/when we are able to get the browsers default styles?

Mockup:

Screenshot 2024-12-12 at 09 13 21

@luminuu
Copy link
Member

luminuu commented Dec 18, 2024

Came here through another issue, I was wondering if it would be possible to add focus-visible and focus-within states as well? These are especially useful for accessibility and it would be great if these would be style-able as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Style Book Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add button interactive state demos in the stylebook
8 participants