WordPress / gutenberg

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

Disabled blocks: identify alternatives to "inert" #54369

Open ramonjd opened 1 year ago

ramonjd commented 1 year ago

Gutenberg's use of "inert"

Gutenberg uses the inert HTML attribute to disable blocks in the editor.

For instance, in the useDisabled hook and on template parts when editing a page in the Site Editor (via useBlockProps).

The assumption is that Gutenberg should have a good reason to disable blocks.

The use of "inert" on disabled blocks impacts accessibility by hiding them from the accessibility tree. In cases where disabled content conveys information in some way, or has, albeit, limited interaction, screen readers/keyboard users have no knowledge of its purpose or existence.

The argument for using "inert" in the editor is that disabled blocks are, as far as the browser and user are concerned, functionally "hidden". They are unfocusable and non-interactive and therefore serve no purpose other than placeholders. Could the editor communicate this intention in another way while retaining "inert"? For example a label that describes the disabled state and what is being disabled?

Related discussions:

Alternatives

I'm not proposing any specific approach, just trying to collate and summarize various discussions.

A proposed approach would be to create a general callback to prevent default behaviour via event handlers, potentially via event delegation/capturing on the editor container. For example, click, focus, keyDown, change etc.

To disable interaction for all core blocks while maintaining keyboard navigation would be challenging. Each core block is unique. Take for example the search block, which contains several focusable elements including a input field and a rich text component.

More time consuming, each block could handle its own disabled state separately. So, the idea is that a block would receive a prop to inform it that it has been "disabled" in the editor and it would render itself accordingly. Perhaps something similar to how the ally library disables elements.

Here's an example of a PR that attempts to accomplish this for the table block:

Questions

Related reading

alexstine commented 1 year ago

Let me start with some thoughts. Its a little after 10PM here so none of these are meant to be taken as mean, but sometimes my point of view can be a little strong.

  1. Inert content is not something that should never be used, it just shouldn't be used for blocks in this way. For example, using inert on content outside of a modal would be a great use of the attribute to prevent any interactions from closing said modal. The modal generally covers much of the page so it is unimportant that screen readers have context for anything outside of modal content.
  2. When using inert on a block, screen reader users do not have an equal experience to sighted users.
  3. Sighted users can clearly see a search form and a submit button in the case of the search block.
  4. Screen reader users would get nothing.
  5. Labels do not meet this requirement because it would be up to developers to describe the block content leaving us with the same problem of accessibility is hard. Simply having a label that says "this block is read-only" still does not give non-sighted users the same experience.
  6. Unlike the disabled attribute, inert totally removes the element or elements from the accessibility tree. Disabled attribute only prevents focus, it does not remove the element from screen readers virtual DOM view.
  7. Let's read the docs together, shall we? https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert

    Prevents the click event from being fired when the user clicks on the element.

Seems reasonable.

Prevents the focus event from being raised by preventing the element from gaining focus.

This is a good first step to making an element inaccessible but it is still accessible via virtual navigation. Not totally broken yet.

Hides the element and its content from assistive technologies by excluding them from the accessibility tree.

This is the final death sentence. At this point, screen reader users are now fully excluded from anything that sighted users may get from seeing the back-end block content. This is essentially the same as aria-hidden="true" with tabindex="-1" with additional event restrictions.

Instead, why not write a hook that does this?

  1. Feed in the block content.
  2. Search for form fields to disable.
  3. Add aria-disabled="true" to communicate disabled to screen readers.
  4. Attach event listeners to prevent click on any element that can receive a click. Hint, this requires valid HTML in the first place. 🙂 Sorry, couldn't resist.
  5. Add some type of description to the block telling users why the content is disabled.

What I can't get over is how this problem started and how it has developed to this point. I am not sure why any developers who work on the project thought it was a good idea to work this hard at making sure blocks match the front-end while simultaneously excluding blind users. Being totally honest, I really don't care if this is how it is done in other editors or websites. Gutenberg should be better than this and I will do my best to help us get there. I enjoy working on Gutenberg because I think it can be better than the status quo but not if everyone keeps comparing it to what already exists on the web. If it were really that simple, I imagine there is no reason for any of us to keep working on Gutenberg in the first place. I see it time and time again. X/Y/Z does it like this...

One final note. The argument about sighted people needing to see content that screen readers don't is not applicable to this situation. Let's think about it.

  1. Screen readers should never be given more information than what is presented to non-screen reader users. This means good UX and great UIs for this to be possible.
  2. This problem was created because using inert, screen readers do not have equal access that someone with sight would have.
  3. If the content is truly not important, let's just remove it from the block all together. It can render on the front-end and no one sees it on the back-end. This allows an equal experience for both non-sighted and sighted users. It would be a pain for both groups of people to constantly need to preview the front-end.

Looking forward to solutions/proposals on how to move this forward.

Thanks.

alexstine commented 1 year ago

BTW, I just gave the search block a test and it looks like inert or disabled are not being used. They are just basic inputs that allow you to customize the output on the front-end. What I can see in the code, the block does not have any type of preview.

youknowriad commented 1 year ago

I've shared more context here https://github.com/WordPress/gutenberg/pull/44865#discussion_r1322616592

Our usage of disabled or/and inert is basically done to mimic images/screenshots, we don't want the content of these divs to be navigable or accessible to sighted or screen reader users, we want these to just be screenshots/previews.

In that sense, I think the solution is to use role="img" with a label when we use that. Just make these containers work like images.

alexstine commented 1 year ago

As I stated in a previous comment, I don't like the idea of allowing subjective labels.

  1. Developers will need to properly describe every element of the block.
  2. Developers will need to remember to update this description when the block changes.

Both of which I am certain will never happen.

Its a good idea but probably not super practical in the real world. I am also trying to figure out how this is solved for 3rd-party blocks.

I'll take it a step further. Instead of using real HTML, why not have the developer take multiple screenshots of the front-end and display them conditionally based on block settings?

Here is a good example. In my Table of Contents block changes, I exposed all the links to screen readers but disabled them. To get the same effect for users, you would need to write a description like this.

Table of Contents block containing a list of headings which are numbered.

  1. X
  2. Y
  3. Z

The description would have to be dynamic so that screen reader users always get the same back-end experience that they would have on the front-end.

The other option? Disable the form controls and stop using inert.

CC: @joedolson @afercia

Maybe they have other opinions that differ from mine.

Thanks.

alexstine commented 1 year ago

First attempt at fixing the comments form block: https://github.com/WordPress/gutenberg/pull/54393

Thinking about this further, @youknowriad is probably correct about some blocks. For example, in comment content, there is no easy way to disable parts of rendered HTML. We have no idea what a user may enter for comments content and this might be one of the situations where disabling the block is necessary. For the blocks that are under our control, I still suggest keeping them as accessible as possible.

joedolson commented 1 year ago

We need to be careful about ensuring that all users have at least a roughly equal access to whatever information is being hidden; and inert doesn't have the same impact on sighted users as it does for screen reader users. There are certainly scenarios where it's reasonable to specify everything as unavailable; we just need to remember that as long as the content is visible, sighted users can read it and know what's in that container; screen reader users don't get that information.

So, if the content is truly intended to be unavailable, why not just replace it with blank space? If it's considered important that the content is visible to some users, then it needs to be visible to all users. So we need a strategy that will expose the relevant information to screen readers or we should not expose any information about the block to sighted users. As it is, we're using a technique that explicitly favors sighted users.

ramonjd commented 1 year ago

Our usage of disabled or/and inert is basically done to mimic images/screenshots, we don't want the content of these divs to be navigable or accessible to sighted or screen reader users, we want these to just be screenshots/previews.

Thanks for the input, everyone.

I'd extend this analogy to the template visualizations surrounding page editing in the site editor. (Related discussion), but I do understand the argument for parity and disclosing what it is we're hiding.

If non-sighted users/keyboard should know more precisely about these areas, perhaps it'd be possible to describe them in general terms and ensure that can be easily "activated" by keyboard, for example, "A header template containing the following blocks: A, B, C.... Click to edit/interact"

This, in my mind, would better match the functionality and offer access to the hidden elements underneath, which in total reflects the behavior of the visual editor.

Ultimately, when editing a page in the Site Editor the only thing one can do is edit the page content unless they explicitly activate template editing.

Once again I'm speaking specifically to the Site Editor's use of inert template areas around a page, not lower level block accessibility concerns such as those address in https://github.com/WordPress/gutenberg/pull/54393.

alexstine commented 1 year ago

@ramonjd Could you please tell me specific steps to edit a page in the Site Editor out of template mode? I want to see it for myself but the Site Editor is still largely confusing to me so want to make sure I can get a look at what I intend to look at.

Thanks.

ramonjd commented 1 year ago

Could you please tell me specific steps to edit a page in the Site Editor out of template mode? I want to see it for myself but the Site Editor is still largely confusing to me so want to make sure I can get a look at what I intend to look at.

Sure! It'd be great to hear about your experience with this journey. As I understand it, the Site Editor still needs a lot of love. Especially, the navigation menus in view mode, which are still relatively new (since WordPress 6.3). It would be great to also know if the navigation needs better labelling too.

Here are the steps:

  1. First go to the Site Editor. Here is the URL path: /wp-admin/site-editor.php
  2. From the navigation list, select the "Pages" item. Here is the URL path: /wp-admin/site-editor.php?path=%2Fpage
  3. From the pages list, select a page other than the home page. E.g., one of the default 2023 theme pages, like "Sample page".
  4. In the single page item view, click on the "Edit" button to enable edit mode in the Site Editor.
  5. From here you should be able to edit the Page's content in the editor. For example, page title, featured image and page content.
  6. To enable template editing, open the page inspector via "Settings" , then "Page".
  7. In the "Summary" pane, select "Template options" to open the menu. Then select "Edit template".

The main functional difference I see, and at first sight I'd consider it an area for improvement, is that mouse users can also activate template edit mode, that is, everything in steps 6 and 7 from the list above, by clicking outside the page content. As far as I can see, this has not yet been implemented for keyboard users.

ramonjd commented 1 year ago

I might add, on the topic of page editing in the site editor: there is a PR in the works that allows toggling the visibility of surrounding (disabled) template areas on and off. The default template visibility will be off it appears from the PR.

alexstine commented 1 year ago

@ramonjd If you look near the end of the hallway hangout, I believe I found this.

https://make.wordpress.org/test/2023/09/14/hallway-hangout-lets-chat-about-improving-accessibility-in-the-site-editor/

You will see where I tried to select the comments form block from the list view and nothing happened. The inert was on the block wrapper and I think that is the same thing you are describing above.

We really need to figure out a better way to handle this.

Thanks.

ramonjd commented 1 year ago

You will see where I tried to select the comments form block from the list view and nothing happened.

Thanks for sharing @alexstine

I think there's definitely a disconnect there between what's happening in the list view and what's in the editor, so I agree that there's some work to be done at the block level here. And/or better synching between the list view and editor block lists.

andrewserong commented 1 year ago

Just linking together that another issue with inert is present in #55177 where the writing flow keyboard navigation is affected by the presence of the inert attribute. There is a short-term workaround for the keyboard behaviour in #55221, but in the longer-term it'd likely be preferable to find an alternative to inert so that when navigating via keyboard, folks can logically move up and down between regular blocks and synced patterns / template parts. (In addition to the other issues already raised in this discussion).

afercia commented 10 months ago

Just noticed that inert is used also for the Disabled component, which wraps some of the blocks in the editor. For example: the Archive block is completely 'empty' for screen readers, regardless whether it set to show a list of a dropdown. Noting is announced or can be interactive with when using a screen reader. It appears it also triggers some unexpected keyboard interaction when tabbing through blocks in the editor.

talldan commented 4 months ago

I was directed here from #62935.

There is already functionality to add a description to a block (via the block label), but I worry that it wouldn't be possible to provide enough information about what's in a block. Especially considering it's often an entire block hierarchy that's made inert.

If you take the example of editing a page with the template visible, a screenreader user should really be able to read the inert parts of the template the same way a sighted user has (use case - making sure the right template is selected). It seems like a big disadvantage that this is not possible without editing the template itself and inspecting the contents. Also some users might not have access to do that based on the user role.

Some kind of read-only mode for html elements would be the ideal solution, but that doesn't exist AFAIK (only for form elements).

I did wonder whether something like renderToStaticMarkup might be a possibility (https://react.dev/reference/react-dom/server/renderToStaticMarkup), but there's the caveat that it'd need to support nested blocks that are enabled.

I'm a bit lacking in other ideas though that don't involve changing every single block's implementation.

joedolson commented 3 months ago

We're able to render blocks on the front-end statically; it seems like we should be able to mimic that in the editor, so that the HTML displays but is no longer editable. I like the idea suggested by @talldan of rendering to static markup; if we can find a good way to do that, it may be worth exploring. It fills the main need: disable editing while still allowing users to perceive the content.

talldan commented 3 months ago

I'm not sure it'd be feasible because of the issue I mentioned about rendering inner blocks within the templates. Also we can't be sure the markup won't need to be updated for particular changes (e.g. are there global styles changes that can cause the block markup to change?), but I put the idea out there to see if it sparked any ideas in others.

ramonjd commented 3 months ago

It's been a while since I looked at this issue, so I don't have all the knowledge/context.

I'm just riffing, but I wonder if there's a way to apply aria-disabled instead of inert and then capture all events on subtree. 🤔

I took a quick look and saw that the rich text block can be told about the block context's editing status:

https://github.com/WordPress/gutenberg/compare/try/replace-inert-on-disabled-editing-block-props