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

useNavigateRegions: Use closest to determine the next region to navigate to #44883

Merged
merged 17 commits into from
Dec 25, 2022

Conversation

alexstine
Copy link
Contributor

@alexstine alexstine commented Oct 11, 2022

What?

This fixes a small bug in region navigation.

Why?

Better accessibility.

How?

Replaced:

		const selectedIndex = regions.indexOf(
			ref.current.ownerDocument.activeElement
		);

This only works if the current element is the region itself so if the user so much as interacts with the content within a region, the user will automatically start at region index 0 or the first region. This is super bad UX. My solution brings us closer to the way it should act with most screen readers but we're still off a bit.
With:

		const selectedIndex = regions.indexOf(
			ref.current.ownerDocument.activeElement.closest( '[role="region"]' )
		);

By using closest, we'll traverse upwards in the HTML until the wrapping region is found. This gives us the index in the regions array so we can best determine previous/next index.

Testing Instructions

The following must be tested with a screen reader enabled such as NVDA. I did my testing in Firefox.

  1. Open the editor.
  2. Press tab to focus the View Posts link.
  3. Press ctrl+` until you land on the Open document settings button.
  4. Press tab a couple times.
  5. Notice how the region navigation is based off where focus is currently placed. This is how screen readers work in-practice, now it is how Gutenberg works.

Screenshots or screencast

@alexstine alexstine added [Type] Bug An existing feature does not function as intended [Type] Enhancement A suggestion for improvement. [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Package] Components /packages/components Needs Accessibility Feedback Need input from accessibility [a11y] Keyboard & Focus [Package] Interface /packages/interface labels Oct 11, 2022
@alexstine alexstine self-assigned this Oct 11, 2022
@alexstine alexstine requested a review from ajitbohra as a code owner October 11, 2022 19:23
@github-actions
Copy link

github-actions bot commented Oct 11, 2022

Size Change: +11 B (0%)

Total Size: 1.32 MB

Filename Size Change
build/components/index.min.js 203 kB +11 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/annotations/index.min.js 2.78 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 487 B
build/block-directory/index.min.js 7.16 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 2.71 kB
build/block-editor/content.css 2.71 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/index.min.js 182 kB
build/block-editor/style-rtl.css 14.7 kB
build/block-editor/style.css 14.7 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 84 B
build/block-library/blocks/avatar/style.css 84 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 485 B
build/block-library/blocks/button/editor.css 485 B
build/block-library/blocks/button/style-rtl.css 532 B
build/block-library/blocks/button/style.css 532 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 100 B
build/block-library/blocks/categories/style.css 100 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 612 B
build/block-library/blocks/cover/editor.css 613 B
build/block-library/blocks/cover/style-rtl.css 1.57 kB
build/block-library/blocks/cover/style.css 1.56 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 253 B
build/block-library/blocks/file/style.css 254 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 984 B
build/block-library/blocks/gallery/editor.css 988 B
build/block-library/blocks/gallery/style-rtl.css 1.55 kB
build/block-library/blocks/gallery/style.css 1.55 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 829 B
build/block-library/blocks/image/editor.css 828 B
build/block-library/blocks/image/style-rtl.css 627 B
build/block-library/blocks/image/style.css 630 B
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/latest-comments/style-rtl.css 298 B
build/block-library/blocks/latest-comments/style.css 298 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 507 B
build/block-library/blocks/media-text/style.css 505 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 716 B
build/block-library/blocks/navigation-link/editor.css 715 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.13 kB
build/block-library/blocks/navigation/editor.css 2.14 kB
build/block-library/blocks/navigation/style-rtl.css 2.22 kB
build/block-library/blocks/navigation/style.css 2.2 kB
build/block-library/blocks/navigation/view-modal.min.js 2.81 kB
build/block-library/blocks/navigation/view.min.js 447 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 376 B
build/block-library/blocks/page-list/editor.css 376 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 174 B
build/block-library/blocks/paragraph/editor.css 174 B
build/block-library/blocks/paragraph/style-rtl.css 279 B
build/block-library/blocks/paragraph/style.css 281 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 501 B
build/block-library/blocks/post-comments-form/style.css 501 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 586 B
build/block-library/blocks/post-featured-image/editor.css 584 B
build/block-library/blocks/post-featured-image/style-rtl.css 318 B
build/block-library/blocks/post-featured-image/style.css 318 B
build/block-library/blocks/post-navigation-link/style-rtl.css 153 B
build/block-library/blocks/post-navigation-link/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 326 B
build/block-library/blocks/pullquote/style.css 325 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 440 B
build/block-library/blocks/query/editor.css 440 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 409 B
build/block-library/blocks/search/style.css 406 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 490 B
build/block-library/blocks/site-logo/editor.css 490 B
build/block-library/blocks/site-logo/style-rtl.css 203 B
build/block-library/blocks/site-logo/style.css 203 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.4 kB
build/block-library/blocks/social-links/style.css 1.39 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 457 B
build/block-library/blocks/table/editor.css 457 B
build/block-library/blocks/table/style-rtl.css 651 B
build/block-library/blocks/table/style.css 650 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 404 B
build/block-library/blocks/template-part/editor.css 404 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 691 B
build/block-library/blocks/video/editor.css 694 B
build/block-library/blocks/video/style-rtl.css 179 B
build/block-library/blocks/video/style.css 179 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 162 B
build/block-library/classic.css 162 B
build/block-library/common-rtl.css 1.05 kB
build/block-library/common.css 1.05 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.7 kB
build/block-library/editor.css 11.7 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 198 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 12.4 kB
build/block-library/style.css 12.4 kB
build/block-library/theme-rtl.css 698 B
build/block-library/theme.css 703 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 50.4 kB
build/components/style-rtl.css 11.6 kB
build/components/style.css 11.6 kB
build/compose/index.min.js 12.3 kB
build/core-data/index.min.js 15.9 kB
build/customize-widgets/index.min.js 11.7 kB
build/customize-widgets/style-rtl.css 1.41 kB
build/customize-widgets/style.css 1.41 kB
build/data-controls/index.min.js 663 B
build/data/index.min.js 8.16 kB
build/date/index.min.js 32.1 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.71 kB
build/edit-navigation/index.min.js 16.2 kB
build/edit-navigation/style-rtl.css 4.11 kB
build/edit-navigation/style.css 4.12 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 34.8 kB
build/edit-post/style-rtl.css 7.44 kB
build/edit-post/style.css 7.42 kB
build/edit-site/index.min.js 65.1 kB
build/edit-site/style-rtl.css 9.06 kB
build/edit-site/style.css 9.06 kB
build/edit-widgets/index.min.js 16.8 kB
build/edit-widgets/style-rtl.css 4.46 kB
build/edit-widgets/style.css 4.46 kB
build/editor/index.min.js 44.1 kB
build/editor/style-rtl.css 3.69 kB
build/editor/style.css 3.68 kB
build/element/index.min.js 4.93 kB
build/escape-html/index.min.js 548 B
build/experiments/index.min.js 882 B
build/format-library/index.min.js 7.2 kB
build/format-library/style-rtl.css 598 B
build/format-library/style.css 597 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.79 kB
build/keycodes/index.min.js 1.86 kB
build/list-reusable-blocks/index.min.js 2.13 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.94 kB
build/notices/index.min.js 977 B
build/plugins/index.min.js 1.95 kB
build/preferences-persistence/index.min.js 2.23 kB
build/preferences/index.min.js 1.35 kB
build/primitives/index.min.js 960 B
build/priority-queue/index.min.js 1.59 kB
build/react-i18n/index.min.js 702 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.75 kB
build/reusable-blocks/index.min.js 2.26 kB
build/reusable-blocks/style-rtl.css 283 B
build/reusable-blocks/style.css 283 B
build/rich-text/index.min.js 10.7 kB
build/server-side-render/index.min.js 2.09 kB
build/shortcode/index.min.js 1.52 kB
build/style-engine/index.min.js 1.53 kB
build/token-list/index.min.js 650 B
build/url/index.min.js 3.7 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 1.09 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.27 kB
build/widgets/style-rtl.css 1.21 kB
build/widgets/style.css 1.21 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@ciampo ciampo requested review from mirka and chad1008 October 13, 2022 10:07
@ciampo
Copy link
Contributor

ciampo commented Oct 13, 2022

Maybe @afercia could help with accessibility feedback here?

Or really anyone with a Windows + NVDA setup (I don't currently have one)

@ciampo ciampo requested a review from afercia October 13, 2022 10:08
@afercia
Copy link
Contributor

afercia commented Oct 13, 2022

Thanks for the ping.
I'll try to test this on Windows, though I'll need to update my local environment which is a bit... old. I'm afraid that will take some time.

However, I'm not sure what kind of problem we're trying to solve.

useNavigateRegions was designed to emulate screen readers native landmarks navigation. It's not primarily designed for screen reader users. Instead, it aims to provide keyboard users who don't use a screen reader a navigation tool similar to the screen readers native one.

Worth reminding all screen readers provide landmarks navigation via dedicated shortcuts, for example:

  • NVDA uses the D key.
  • VoiceOver provides landmark navigation via the 'rotor'.
  • JAWS uses the R key (if I remember correctly).

Improvements are always welcome but at first glance seems to me it's important to keep useNavigateRegions as close as possible to the native screen readers feature and not introduce changes. Will test to check if there's anything broken in the current implementation (the focus style is for sure) and then test the proposed changes.

@ciampo
Copy link
Contributor

ciampo commented Oct 13, 2022

Improvements are always welcome but at first glance seems to me it's important to keep useNavigateRegions as close as possible to the native screen readers feature and not introduce changes.

This was my gut feeling too — I usually prefer not to interfere with standard browser/screen reader behavior when possible!

I'd be curious to hear more in details why these changes are being proposed in the first place, and if anyone else could also chime in to help assess the potential problem and its proposed solution.

@alexstine
Copy link
Contributor Author

These changes are being proposed because the current behavior is not accurate. I have recorded a screen share with audio to show how and why this should be improved.

@afercia The reason why we should not rely on landmark navigation with screen readers is also explained. Gutenberg requires stuff the accessibility spec is still lacking on so I have found a work-around just like other apps including Slack, Teams, and many others. Having a centralized way to move around that is not screen reader specific is a win every time.

https://drive.google.com/file/d/1DKeUpy26nr-fNiXkEmTl4X1zFbgRzLVh/view?usp=sharing

Hope this helps.

I am still planning on refining this a bit further. Just have not had the time.

Thanks.

@alexstine
Copy link
Contributor Author

Okay, this is a complete solution now.

  1. No matter where you are in the editor, navigating next will focus the next tabbable item in the next region.
  2. No matter where you are in the editor, navigating previous will focus the previous tabbable item in the previous region.
  3. This follows the exact same pattern NVDA navigation does but this comes with the advantage of taking control of the screen reader mode switching.
  4. I modeled this after Teams and Slack with ctrl+f6 in Teams and f6 in Slack. When pressing these keys, it finds the next region and places focus on the content within it so the screen reader knows to switch modes. This saves a step with users constantly having to switch modes, we're handling it for them.

I honestly do not expect most people will understand this, it is fairly high-level workings of how screen readers work. However, I do hope this gets further review because I believe this could impact Gutenberg for the better.

Thanks.

@ciampo
Copy link
Contributor

ciampo commented Oct 14, 2022

As you mentioned, reviewing this PR properly requires the reviewer(s) to have deep familiarity with how a screen reader works — since I don't, I will keep an eye on this PR and facilitate the review process if needed but I don't think I can be the main reviewer.

A couple of things that I wanted to point out:

  • It sounds like we're implementing a behaviour that is specific to NVDA — would folks using a different screen readers feel disoriented ?
  • It also sounds like the behavior is modelled after MS Teams and Slack — similarly to the previous point, is it a good idea to implement a custom behavior for navigating regions, instead of just following the browser/screen reader standards?
  • There are some related failures in the e2e tests

@alexstine
Copy link
Contributor Author

alexstine commented Oct 14, 2022

@ciampo Answers.

It sounds like we're implementing a behaviour that is specific to NVDA — would folks using a different screen readers feel disoriented ?

No, this is common pattern across all screen readers. NVDA and Voiceover are free, that is why I suggest testing with them.

It also sounds like the behavior is modelled after MS Teams and Slack — similarly to the previous point, is it a good idea to implement a custom behavior for navigating regions, instead of just following the browser/screen reader standards?

What I am trying to explain is the current version does not follow such standards. Placing focus on a negative tabindex of a region is not how any other screen reader handles it. Slack and Teams got this right.

The E2E tests are beyond me right now, I just want to get some feedback started.

I will also give this a test with Voiceover and JAWS over the weekend.

The important take-away here is this does not follow standards, my PR makes it follow more closely to what those standards are. Now it can be the same for everyone, screen reader or not.

Thanks.

@alexstine
Copy link
Contributor Author

@ggordon-vispero If you have some spare time, could you please sanity check this one for me? I believe this brings our region navigation more in-line with how screen readers work. Feel free to disagree.

You can test at: http://gutenberg.run
Enter PR number: 44883
Navigate to the next part of the editor: Shift+Alt+N
Navigate to the previous part of the editor: Shift+Alt+P

As mentioned earlier in the PR, I tried to replicate what Slack has been doing with F6. I really enjoy how it places focus on the first tabbable since it can assist in switching screen reader mode automatically.

Please let me know if you need more context.

Thanks.

@afercia
Copy link
Contributor

afercia commented Oct 17, 2022

@alexstine thanks for the video and the clarifications. I know that requires patience and some effort.

To my understanding, we can maybe split this in 4 main points:

  1. NVDA reads the entire content of the focused region.
  2. Move focus to the first focusable instead of to the region.
  3. Cycle through regions starting from the current region.
  4. Empty tab stops.

On a general note, as mentioned earlier, this feature was originally designed for sighted keyboard users. I'm not sure optimizing this feature for screen readers is the way to go. We need to cover diverse needs of a divers range of users. I do believe that, in the long term, education is way more effective. I get one of your concerns is that many screen reader users don't know how to use native landmarks navigation. It would be great to educate them by the means of some good help guide instead of implementing hyper-technical solutions. Native features are always better.

That said, I'm all for improvements. There are a few problems though.

NVDA reads the entire content of the focused region.

I'm afraid this is more a NVDA quirk rather than something we should fix. JAWS doesn't exhibit this behavior. VoiceOver neither. They just announce the region aria-label, as expected. I think we should report upstream this issue to NVDA. To me, when a landmark region receives focus and the region is labelled, NVDA should read only the label. I made a simplified codepen with 3 different tests, to make testing with various screen readers easier at https://codepen.io/afercia/full/PoegWdR

Move focus to the first focusable instead of the region.

It's important to note that the screen readers native landmarks navigation doesn't actually move focus. It moves the virtual cursor. This matters because the virtual cursor can move to any element, even the non-focusable ones. That is: if a landmark starts with a heading, or a paragraph, or a list, etc., landmarks navigation jumps to the landmark, moves the virtual cursor to the first element and announces it. This native behavior can be easily tested on the W3C landmark example pages, for instance at https://www.w3.org/WAI/ARIA/apg/example-index/landmarks/region.html
Instead, the proposed approach in this PR moves focus to the first focusable element. This would be risky because it would skip any non-focusable content placed at the start of a region. I guess we don't want users to miss content.

It's not the only problem though. Turns out that setting and removing the tabindex attribute as proposed in this PR doesn't work well in Chrome. See the third test on the codepen. With Chrome, removing the tabindex triggers a focus loss both with NVDA and JAWS. Nothing is announced.

Lastly, there's a visual thing to take into consideration. The current useNavigateRegions feature is supposed to draw a thick blue outline around the region that receives focus. Note that this is partially broken right now and works well only on the top bar and on the footer (reported on #21717 more than 2 years ago). We should fix it but, regardless, the outline is designed to help sighted keyboard users in understanding what region is the currently focused one. This would be lost if we change to focus the first focusable element. As a low vision user, I really struggle to see where focus is when I use regions navigation with the changes from this PR.

Overall, I wouldn't recommend to move focus to the first element. We shouldn't optimize for screen readers only. We should always try to help the broadest range of users. Screen reader users can use the native landmarks navigation: it works better and we should educate them on how to use it.

Cycle through regions starting from the current region.

This would be a great improvement and I'd be all for it. RIght now, region navigation starts again from the first region and that's not ideal. It makes totally sense to start from the next region.

Empty tab stops.

I'm not sure the empty tab stops you mention in your video are related to the negative -1 tabindex set on the regions. A negative tabindex shouldn't have any effect on the tab sequence, as it makes an element programmatically focusable but the element isn't included in the tab sequence. Instead, I noticed some empty tab stops before and after the currently selected block. Those tab stops are pretty confusing. I think they come from the component that manages focus on the selected element. I just haven't had time to investigate further but seems to me this implementation is less than ideal. Not related to the regions though.

@alexstine alexstine force-pushed the try/removing-tabindex-from-toolbars branch from 745c9a0 to faefdc3 Compare October 31, 2022 12:56
@alexstine
Copy link
Contributor Author

@ellatrix I tried a git rebase origin/trunk. I have not really done branch rebase before, hopefully this was the way.

@alexstine
Copy link
Contributor Author

@youknowriad @kevin940726 Do you have any ideas why these tests are still failing? This is far beyond my ability to debug at this point.

@kevin940726
Copy link
Member

The playwright test is failing because we didn't update them in a11y-region-navigation.spec.js. Perhaps @afercia would know better how to correct them? It seems to me that we just need to add a couple more of page.keyboard.press( 'Control+' )but I'm not entirely sure. I think it would be nice if we could add some comments to thosepress()` functions to state where we're currently focusing on.

@alexstine
Copy link
Contributor Author

Thanks @kevin940726 ! I think I managed to fix this up.

@alexstine alexstine added the [Package] E2E Tests /packages/e2e-tests label Nov 14, 2022
@alexstine
Copy link
Contributor Author

@kevin940726 Do you know why the main E2E tests are still failing? Playwright is resolved, but I can't tell if my changes are causing test failures or if they are just flaky test related.

@kevin940726
Copy link
Member

I think it's the same issue, we need to update the test to reflect the changes made here in:

@alexstine
Copy link
Contributor Author

@kevin940726 Thanks! Those logs are always so confusing, I missed it.

@afercia Could you please check this and approve so this fix can be merged in?

Thanks.

@youknowriad
Copy link
Contributor

Hi @afercia I see you still have a blocking review here. Did the recent changes and discussion address your points raised above? What's remaining here?

@youknowriad youknowriad dismissed afercia’s stale review December 20, 2022 09:02

Removing this blocking review as it looks like these were addressed, if there's still something remaining, please let us know. Thank you

@alexstine alexstine merged commit 6051295 into trunk Dec 25, 2022
@alexstine alexstine deleted the try/removing-tabindex-from-toolbars branch December 25, 2022 22:01
@github-actions github-actions bot added this to the Gutenberg 14.9 milestone Dec 25, 2022
@afercia
Copy link
Contributor

afercia commented Dec 27, 2022

Sorry I missed the pings. Thanks everyone for this cool improvement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). Needs Accessibility Feedback Need input from accessibility [Package] Components /packages/components [Package] E2E Tests /packages/e2e-tests [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants