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 summary prop to PanelBody, and use it to create more accessible pre-publish panel sections. #25170

Closed
wants to merge 5 commits into from

Conversation

ZebulanStanphill
Copy link
Member

@ZebulanStanphill ZebulanStanphill commented Sep 9, 2020

Description

Giving buttons titles like "Visibility: Public" is not ideal for accessibility. See #470 (comment). But currently, we have a few disclosure widgets in the prepublish panel that use this anti-pattern.

This PR tries to solve that by showing the same info in a different way: it introduces a new summary prop to <PanelBody> that let's you show a summary of the panel's contents when the panel is closed, without messing up the label of the actual button to open the section.

This PR also improves the semantics of <PanelBody> so it uses a <section> as its root element, and a <header> to wrap both the clickable header and the summary below. While this was not strictly necessary, I figured that since I had to alter the markup anyway (by adding a wrapping element to contain both the title and new summary), I might as well improve the semantics while I'm at it. I have reverted to simply using <div>s to keep the changes in this PR smaller. We can always come change this is a future PR.

The PR also currently alters two of the pre-publish panel sections as a demonstration. This can be cut out before merge and discussed in a separate PR to refine the specific text, or it can be kept at merge if desired.

image
image

I need feedback to ensure the current implementation is as accessible as it should be. Note that I have intentionally not made the summary clickable to open the section. Allowing it to be clicked may complicate the semantics and undo the whole point of trying to more accessible. I am not sure what works in an a11y context here, and would appreciate any feedback. Would moving the onClick handler to the <header> element be okay, or would that break a11y?

I am also not certain if the summary should disappear when the section is expanded, or whether it should always be visible. I currently make it disappear, but I am again uncertain how this affects a11y. The summary is now always visible.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@ZebulanStanphill ZebulanStanphill added [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). Needs Design Feedback Needs general design feedback. [Feature] UI Components Impacts or related to the UI component system Needs Accessibility Feedback Need input from accessibility [Type] New API New API to be used by plugin developers or package users. labels Sep 9, 2020
@github-actions
Copy link

github-actions bot commented Sep 9, 2020

Size Change: +165 B (0%)

Total Size: 1.2 MB

Filename Size Change
build/components/index.js 200 kB +75 B (0%)
build/components/style-rtl.css 15.5 kB +20 B (0%)
build/components/style.css 15.5 kB +19 B (0%)
build/editor/index.js 45.7 kB +51 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.67 kB 0 B
build/api-fetch/index.js 3.41 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 8.54 kB 0 B
build/block-directory/style-rtl.css 953 B 0 B
build/block-directory/style.css 952 B 0 B
build/block-editor/index.js 128 kB 0 B
build/block-editor/style-rtl.css 11.1 kB 0 B
build/block-editor/style.css 11.1 kB 0 B
build/block-library/editor-rtl.css 8.68 kB 0 B
build/block-library/editor.css 8.68 kB 0 B
build/block-library/index.js 139 kB 0 B
build/block-library/style-rtl.css 7.59 kB 0 B
build/block-library/style.css 7.58 kB 0 B
build/block-library/theme-rtl.css 754 B 0 B
build/block-library/theme.css 754 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 47.8 kB 0 B
build/compose/index.js 9.68 kB 0 B
build/core-data/index.js 12.3 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/data/index.js 8.54 kB 0 B
build/date/index.js 31.9 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 4.47 kB 0 B
build/edit-navigation/index.js 11.7 kB 0 B
build/edit-navigation/style-rtl.css 1.16 kB 0 B
build/edit-navigation/style.css 1.16 kB 0 B
build/edit-post/index.js 305 kB 0 B
build/edit-post/style-rtl.css 6.26 kB 0 B
build/edit-post/style.css 6.25 kB 0 B
build/edit-site/index.js 19.3 kB 0 B
build/edit-site/style-rtl.css 3.06 kB 0 B
build/edit-site/style.css 3.06 kB 0 B
build/edit-widgets/index.js 12.2 kB 0 B
build/edit-widgets/style-rtl.css 2.55 kB 0 B
build/edit-widgets/style.css 2.55 kB 0 B
build/editor/editor-styles-rtl.css 492 B 0 B
build/editor/editor-styles.css 493 B 0 B
build/editor/style-rtl.css 3.81 kB 0 B
build/editor/style.css 3.81 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.72 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 621 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 710 B 0 B
build/keyboard-shortcuts/index.js 2.52 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.12 kB 0 B
build/list-reusable-blocks/style-rtl.css 476 B 0 B
build/list-reusable-blocks/style.css 476 B 0 B
build/media-utils/index.js 5.32 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.41 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 13.9 kB 0 B
build/server-side-render/index.js 2.77 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.85 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@ZebulanStanphill ZebulanStanphill force-pushed the add/panel-body-summary-prop branch from 071597c to d775c41 Compare September 9, 2020 03:34
@ZebulanStanphill ZebulanStanphill force-pushed the add/panel-body-summary-prop branch 2 times, most recently from dcff01e to 2a4456f Compare September 9, 2020 14:41
@afercia
Copy link
Contributor

afercia commented Sep 9, 2020

Cool, thanks @ZebulanStanphill !

This would finally solve #470 by splitting the button action, which needs to be communicated by the button text (accessible name in the accessibility tree) by the state, which needs to be communicated separately. Totally in favor of this approach 🎉

Tested it on both Windows and macOS. On Windows Firefox + NVDA it works like a charm:

Screenshot (128)

On macOS, for some reason Safari and VoiceOver do not announce the description 🙁 I think it's some weirdness with VoiceOver. To be sure it's not something related to some JS or CSS, I made a reduced test case on this codepen: https://codepen.io/afercia/full/bGpvGjK. The examples there have slight variations in the HTML and for some of them the description gets announced, for others it doesn't. Sometimes some screen readers are very sensible to what they consider "unexpected" markup. There are a few options to solve this issue with their pros and cons. In general, I'd recommend to keep the markup as simple as possible.

Other minor notes:

Not sure the section and header elements are really necessary. These panels are basically accordions and a list of headings with their panels should be enough. Also, I'm not sure assistive technologies communicate in any way the semantics of section and header.

Would moving the onClick handler to the <header> element be okay, or would that break a11y?

Hm, I'd say only the button should have a click event. Making a non-interactive element interactive would require to assign it a role (button?), replicate the expected interaction, add a focus style, etc. And at that point there would be two nested interactive elements. If the purpose it to extend the clickable area on the description, maybe there are CSS tricks to do that or maybe we shouldn't do it in the first place :)

I am also not certain if the summary should disappear when the section is expanded, or whether it should always be visible. I currently make it disappear,

I was initially concerned about the disappearing of the description. Preferably, it should stay visible. If design prefers to hide it when the panel opens, after all users have the full info available within the panels.

Lastly, I'm not sure this pattern to build the strings is good for translations:

__( 'Set to <PostVisibilityLabel />.' )
__( 'Set to <PostScheduleLabel />.' )

Ideally, there shouldn't be "variable parts" within a string. I do realize it isn't possible to build specific strings for all the possible cases (especially for the publish date/time). Maybe worth considering to move out the variable part from the strings and use only __( 'Set to:' ) with some good translators comments?

@ZebulanStanphill ZebulanStanphill force-pushed the add/panel-body-summary-prop branch from b108034 to a781ba2 Compare September 9, 2020 15:59
@ZebulanStanphill
Copy link
Member Author

Interesting that on VoiceOver, the description gets announced when its inside the h2. But that's not semantically correct, is it? Actually, that's part of the reason why I went using the header and section elements in the first place. The description is in the "header area" of the accordion, but it's not actually part of the section title, so I put both the h2 and the summary div inside a header. I wasn't sure if the header would receive proper semantics outside of a section, so I figured I'd just turn the accordion into a section... since that's what it already was conceptually anyway.

I'm not really sure what to do here. Putting the description inside the h2 is clearly wrong, isn't it? At least from your tests, it looks like the usage of section and header versus just plain divs doesn't have any negative effect on how screen readers perceive the component.

As for the whole onClick thing, I can't really think of any CSS trickery that would work without being super hacky and fragile. So I'll just leave the summary static.

I've altered the component to keep the summary visible when the section is expanded.

I've also adjusted the pre-publish section summary strings as you suggested. I wasn't really sure what to put in the translator comments. So please check those out and let me know what you think.

image

@afercia
Copy link
Contributor

afercia commented Sep 9, 2020

Interesting that on VoiceOver, the description gets announced when its inside the h2. But that's not semantically correct, is it?

Yeah... When it comes to screen readers it's like going back in time 15 years and have to struggle again with browser quirks everywhere... screen readers are similar to those old browsers. They have lots of quirks, sometimes triggered by the way browsers expose information, sometimes it's just the screen reader.

Yep the description wouldn't be great inside the h2. I could live with the visibility one, but the publish date/time would be terrible. Also, this is a generic reusable component to it needs to suit many cases.

At least from your tests, it looks like the usage of section and header versus just plain divs doesn't have any negative effect on how screen readers perceive the component.

It seems it doesn't. But it also doesn't have any benefit? Semantics is not an abstract thing that "works out of the box". And it's not for humans. It's only perceived by software and when software don't communicate a specific semantic structure to users maybe that semantics is redundant? :)

@ZebulanStanphill
Copy link
Member Author

I would have thought the <section> would at least add the section role to the accordion. Does that not mean anything to screen readers? I also figured that using the elements would be more "future-ready", and since I needed to use container elements anyway, I might as well use the "proper" ones. But I can switch back to divs if you want.

(Actually, come to think of it, why is PanelBody not called PanelSection?)

So what do we do about the VoiceOver thing? Which is better: the current design, or having the description inside the heading?

@afercia
Copy link
Contributor

afercia commented Sep 10, 2020

I'd lean towards keeping the markup simple, for now.

(Actually, come to think of it, why is PanelBody not called PanelSection?)

🤷 Yep. Actually, these are accordions. Maybe they should be named for what they are 🙂 In the future we may want to consider to implement some missing bits of the expected interaction, namely: arrows navigation through the accordion headers. See https://www.w3.org/TR/wai-aria-practices-1.1/#accordion

So what do we do about the VoiceOver thing? Which is better: the current design, or having the description inside the heading?

Unfortunately, the description inside the heading would be incorrect. I gave it another round of testing and updated the codepen. Couldn't find a clean solution though. 😞 To me, this seems a Chromium bug. Chrome and Opera (on macOS) show the same buggy behavior. I can't think of a workaround off the top of my head. Asked around on Twitter, maybe someone in the hope someone else can help.

@afercia
Copy link
Contributor

afercia commented Sep 10, 2020

Noting that VoiceOver users can always explore the content by arrowing (Control Option Right or Left arrow keys) so the state is available for them, in a way. Clearly, it would be great to have the description be announced also when they Tab through the buttons.

@ZebulanStanphill ZebulanStanphill force-pushed the add/panel-body-summary-prop branch 2 times, most recently from bc1a0f1 to 648d3fc Compare September 10, 2020 16:26
@ZebulanStanphill ZebulanStanphill force-pushed the add/panel-body-summary-prop branch from fd90c9a to a22a178 Compare September 10, 2020 17:01
@ZebulanStanphill
Copy link
Member Author

I'd lean towards keeping the markup simple, for now.

I've reverted to plain <div>s. We can always revisit this in a future PR.

@alexstine
Copy link
Contributor

I had some feedback while this is open. These are the changes I would recommend making, but not sure how many of these are truly feasible for this PR and maybe they just need to be dealt with in the future.

  1. The pre-publish panel should be a dialog. Something that screen readers cannot get out of. If I switch in to browse mode inadvertently, I can go anywhere else on the page. Since the panel does not open up right underneath the "Publish" button, more should be done to restrict the movement of users.
  2. The dialog should contain a heading with text like "Ready to Publish? Check over the settings below." This should be the aria-labelledby.
  3. The first button should be the "Close" button. Having the focus put on the "Publish" button, users may be more likely to click that button and may not see other settings.
  4. The "Publish" button itself should be at the very end of the dialog. That way users must tab through the other settings in the dialog before publishing. Making the dialog behave like this will ensure the users navigate through the other settings before confirming their choice of publishing.

Sorry if all of this is out of the scope of this PR. I do like the changes here and it does make the panel much more accessible. Those items above are really just dreams from me I think, but it would make it a lot better functioning in my opinion.

Thoughts?

@afercia
Copy link
Contributor

afercia commented Sep 12, 2020

@alexstine thanks for testing and for your feedback.

I definitely agree that modal dialogs and well-implemented disclosure widgets are way more understandable and easy to use.

To clarify a bit: right now, visually this looks like a Sidebar. That is: a column that slides in into the page from the right. We're going to discuss this Sidebar pattern more in depth in the next weekly accessibility meetings as we think it's far from ideal.

To provide more in-depth feedback on the Sidebar pattern, I'd recommend to start from this new issue about the Inserter sidebar: #24975

A couple things:

  • focus on the Publish button: right, it would be nice to consider the idea to swap the position of the Publish and Cancel buttons so that initial focus goes to the Cancel one
  • Publish button placed at the end: I know: I insist on this point since years... no luck so far.

I'd like this feedback from @alexstine to be well considered by the designers involved in the Gutenberg project as it well illustrates the struggles users have with some design patterns. Cc'ing @mapk

@ZebulanStanphill
Copy link
Member Author

@alexstine I agree with all of your suggestions, but it's certainly outside this particular PR's scope. If I have the spare time, I might try implementing your ideas in a separate PR later. (Or if anyone wants to go ahead and jump on that themselves, feel free to do so.)

@enriquesanchez
Copy link
Contributor

Hi @ZebulanStanphill 👋

Thanks for working on this. I have some design feedback on the placement of the summary prop and the overall focus area.

Right now the summary prop feels very disconnected from the panel heading and in general feels out of place with the rest of the other panels that don't show a summary prop.

We can work around that if we align the summary closer to the heading, something like this:

Frame 95

Notice how the label is closer to the heading and the toggle arrow on the right is center aligned.


As for focus, it also currently feels very disconnected and it's weird that only half of the panel collapsed area is clickable. I think it's important we make the whole panel collapsed area focusable:

Frame 96


I undertand this PR is aimed for 5.6, I hope these suggestion can be ready on time 👍

Again, thank you for working on this.

@ZebulanStanphill
Copy link
Member Author

@enriquesanchez I think I can do that first thing. As for the second thing, however...

As for focus, it also currently feels very disconnected and it's weird that only half of the panel collapsed area is clickable. I think it's important we make the whole panel collapsed area focusable:

I have no clue how to do this. If anyone has any suggestions, please let me know. Remember, the summary must not be inside the <button>.

@enriquesanchez
Copy link
Contributor

I have no clue how to do this. If anyone has any suggestions, please let me know. Remember, the summary must not be inside the .

@ZebulanStanphill 🤔 Maybe we can keep it out of the <button>, but still place it below the label? position: relative; comes to mind as something to try out but I'm sure it won't be that simple, as the summary will block the target area.

@ZebulanStanphill
Copy link
Member Author

@enriquesanchez Yeah, that's what I was thinking, but I can't figure out a way to actually pull it off. A problem I keep running into is that the button needs to take up the entire click area of the header without changing the height of it.

I get the feeling that any solution is going to feel really hacky and convoluted. Is it really worth it to have the summary be clickable? I'm starting to think not. Maybe we could find some other way to adjust the styles to make it look nicer instead of trying to make something look/act like it's part of a button without actually being part of it.

Maybe the expand/collapse icon would feel less awkward if it was placed next to the button text instead of all the way to the right.

@enriquesanchez
Copy link
Contributor

@ZebulanStanphill I took a stab and I think I got it working, here's a POC in Codepen: https://codepen.io/enriquesanchez/pen/qBNqvzy

What I'm doing is set pointer-events: none; on the panel summary, so this way it doesn't interfere with the button's click events. In my testing, focus works as expected and I'm still able to reach and hear the summary with VoiceOver's virtual cursor.

Do you think we can try this for this PR?

@ZebulanStanphill
Copy link
Member Author

@enriquesanchez In my experiments, I did something similar. The unsolved problem is that the positioning/sizing doesn't account for the title or summary taking up multiple lines. I can't think of a way to set the height/positioning properly using just CSS, and I don't want to resort to using JS.

@enriquesanchez
Copy link
Contributor

@ZebulanStanphill Gotcha, I gave this another try. Here's another attempt that covers the case when the summary is multiple lines and the container needs to grow vertically: https://codepen.io/enriquesanchez/pen/yLJXddr

The button is still focusable/clickable and covers the full width and height of the panel container.

@ZebulanStanphill
Copy link
Member Author

@enriquesanchez It looks like your demo doesn't work right on Chrome:

image

It looks fine on Firefox:

image

However, in both cases, while it does resize based on the number of lines the summary takes up, it still doesn't account for the section title taking up multiple lines.

@afercia
Copy link
Contributor

afercia commented Oct 28, 2020

it still doesn't account for the section title taking up multiple lines.

Yep, absolute positioning should be avoided also thinking at text-only zoom.

There are CSS tricks to achieve the desired layout, for example by using CSS pseudo elements but they're sort of hacks anyways. I'd suggest to avoid hackish solutions.

First, I'd consider a design solution that fits with the desired feature. Function should come first, visuals later.

What is needed here is:

  1. a button to expand the panel
  2. a description, semantically associated with the button and placed outside the button
  3. the button doesn't necessarily need to look like a "panel header" so I'd expect a design that makes 1) and 2) possible

Base automatically changed from master to trunk March 1, 2021 15:44
@ZebulanStanphill
Copy link
Member Author

Having thought about it for a while, I really don't see any way to get this PR working both visually and functionally with the current design. Because of this dead end, I'm closing this PR.

I think something like this might make for better UI:

-----------------------------
Visibility: Public     [Edit]
-----------------------------

The [Edit] would be the only actual <button>, and the surrounding text could redirect clicks to that button. Perhaps it should even open a pop-up modal, rather than use an accordion. The recent changes to the style controls in the block inspector do seem to be moving away from accordions, now that I think about it.

Either way, such changes are different enough to warrant a new PR, and I encourage anyone interested in this idea to pursue it, because I currently do not have the spare time to do so. Hopefully, the discussion in #39082 will produce a UI pattern that works in both the Document Settings sidebar and pre-publish panel.

@ZebulanStanphill ZebulanStanphill deleted the add/panel-body-summary-prop branch July 28, 2022 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] UI Components Impacts or related to the UI component system [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). Needs Design Feedback Needs general design feedback. [Type] New API New API to be used by plugin developers or package users.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants