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

Fix constrained tabbing failures with Safari and Firefox #47426

Merged
merged 11 commits into from
Feb 14, 2023

Conversation

afercia
Copy link
Contributor

@afercia afercia commented Jan 25, 2023

Fixes #46041
Fixes #41500

What?

The refactoring of useConstrainedTabbing in #34836 introduced a few regressions and unexpected behaviors. Some of these regressions have been fixed already, see for example #42652, #45903, ,and #42653.

This PR aims to fix one remaining regression with Safari and some unexpected behavior with Firefox.

TL;DR

The regression and unexpected behaviors surfaced only when attempting to run the existing editor/various/a11y.spec.js test with all browsers in #46038. The outcome was 1 failure with webkit (Safari) and 2 failures with Firefox.

That proved the native browsers behavior differs in some cases. Therefore, the current implementation of useConstrainedTabbing, which relies on native browser behavior, doesn't appear to be ideal in the first place.

I'd like to note that when it comes to some accessibility features, it is very, very important to run E2E tests with all ajor browsers. In fact, it turned out browser behavior differs in at least two cases:

  • Safari: when clicking somewhere after the last tabbable within a modal dialog and then pressing Tab, the modal dialog closes unexpectedly. Instead, wIth Chrome and Firefox the tab sequence restarts from the previous tababble. This seems related to the so called Sequential focus navigation starting point, which is a browser feature that is apparently implemented differently in Safari.
  • Firefox: it's the only major browser that natively makes scrollable elements focusable. The useConstrainedTabbing current implementation allows to tab to scrollable elements but it doesn't take them into account as 'tabbable' elements, leading to unexpected behavior.

I'd also like to kindly note that it appears the refactoring in #34836 didn[t introduce any new test for the specific use case it was meant to address, see https://github.com//issues/34681. I will create a separate issue for that.

Why?

The constrained tabbing feature is broken since more than one year now. It needs to work reliably and consistently across all major browsers. It also needs to be tested more effectively.

How?

  • Adds some actual focus management when a tabbable element contains the next tabbable element. In this case, Safari seems to disagree with other browsers when there is no focused element and the 'Sequential focus navigation starting point' feature comes into play.
  • Determines whether the modal dialog content is scrollable, that is: when there is an actual content overflow.
  • Makes the scrollable div focusable, only when there is an actual content overflow. This reproduces the native Firefox behavior for all browsers.
  • Use ResizeObserver to listen to the modal dialog content size changes and checks again whether it's scrollable. This is necessary because:
    • When resizing browser window, zooming in/out, changing orientation on mobile devices, etc., the content may overflow or not depending on the actual size of the content area.
    • Sometimes the modal dialog content is dynamic so that its size changes on the fly, e.g. the Preferences modal uses tabs. Some tabs produce a content overflow, some don't.
  • Wraps the dialog content within a <div> element: this is necessary to determine size changes via ResizeObserver.
  • Adds aria-label="Scrollable section" tabindex="0" to the dialog content when it's scrollable
  • Adds a scrollableContentLabel prop that can be used to override the default label Scrollable section.
  • Adds a basic focus style to the content when it's scrollable and focusable.
  • Makes the a11y E2E test run also with Firefox and Webkit.
  • Adds E2E test for the scrollable section.

Note:

  • I opted to not use useResizeObserver for now. I'm not sure I like the current implementation which injects an additional <div> element and overlays it on the node to check for resizing. Also, that works only when the node to check for is a positioned element.
  • It would be great to abstract and futher improve the scrollable section functionality in Improve the Scrollable component accessibility #45809. Before that, it would be great to wait for Support a new API for useResizeObserver #41001 which aims to refactor useResizeObserver so that it can be used directly on an element. /Cc @youknowriad

Testing Instructions

  • Run npm run test:e2e:playwright -- --headed editor/various/a11y.spec.js and check the tests pass.
  • Edit a post and open the Keyboard shortcuts modal dialog.
  • Tab through the elements within the modal dialog and check the list of shortcuts container receives focus and shows a focus style.
  • With the scrollable element focused, check you can scroll the element by using the Down and Up arrow keys or the Spacebar / Shift+Spacebar. With Safari you may need to press Fn+Down/Up arrow.
  • Check you can cycle through the Close button and the scrollable element by pressing Tab and Shift+Tab.
  • Close the Keyboard shortcuts modal dialog and open the Preferences one.
  • Depending also on your screen size, the General tab should not produce content overflow so it should not be scrollable.
  • Inspect the source and check the content area, that is the element with role=document does not have an aria-label attribute nor a tabindex attribute.
  • Click on the Blocks tab. This tab has longer content and, depending also on your screen size, it should be scrollable.
  • Check the content area is now scrollable and does have aria-label="Scrollable section" tabindex="0" attributes.
  • Type qwerty in the 'Search for a block' search field.
  • The modal dialog content will be shorter and only display 'No blocks found'.
  • Check the content area is no longer scrollable nor focusable.
  • Check it does not have an aria-label attribute nor a tabindex attribute.
  • Clear the search field. The content will show the long list of blocks again.
  • Check the content area is scrollable and focusable again.
  • Check it does have aria-label="Scrollable section" tabindex="0" attributes.
  • Check there are no visual regressions in other modal dialogs e.g.:
    • the 'Explore all patterns' modal dialog
    • the confirm dialog when switching back to a draft
    • the confirm dialog when changing post visibility to 'Private'
    • the 'Lock block' modal dialog
    • the Query loop block > 'Choose a pattern' modal dialog
    • any other complex modal dialog e.g. in the Site Editor

Testing Instructions for Keyboard

See above.

Screenshots or screencast

@afercia afercia added [Type] Bug An existing feature does not function as intended [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Regression Related to a regression in the latest release [Package] Compose /packages/compose [a11y] Keyboard & Focus labels Jan 25, 2023
@github-actions
Copy link

github-actions bot commented Jan 25, 2023

Size Change: +677 B (0%)

Total Size: 1.33 MB

Filename Size Change
build/block-editor/index.min.js 193 kB +444 B (0%)
build/block-library/index.min.js 200 kB -4 B (0%)
build/components/index.min.js 206 kB +157 B (0%)
build/components/style-rtl.css 11.7 kB +19 B (0%)
build/components/style.css 11.7 kB +19 B (0%)
build/compose/index.min.js 12.4 kB +23 B (0%)
build/edit-site/index.min.js 64.6 kB +19 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 483 B
build/block-directory/index.min.js 7.2 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.11 kB
build/block-editor/content.css 4.1 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/style-rtl.css 14.4 kB
build/block-editor/style.css 14.4 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 91 B
build/block-library/blocks/avatar/style.css 91 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 587 B
build/block-library/blocks/button/editor.css 587 B
build/block-library/blocks/button/style-rtl.css 628 B
build/block-library/blocks/button/style.css 627 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 265 B
build/block-library/blocks/file/style.css 265 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 830 B
build/block-library/blocks/image/editor.css 829 B
build/block-library/blocks/image/style-rtl.css 652 B
build/block-library/blocks/image/style.css 652 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 134 B
build/block-library/blocks/post-excerpt/style.css 134 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 458 B
build/block-library/blocks/query/editor.css 457 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 149 B
build/block-library/blocks/rss/editor.css 149 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 433 B
build/block-library/blocks/table/editor.css 433 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 552 B
build/block-library/blocks/video/editor.css 555 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 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 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.6 kB
build/block-library/editor.css 11.6 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 12.6 kB
build/block-library/style.css 12.6 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 51 kB
build/core-data/index.min.js 15.9 kB
build/customize-widgets/index.min.js 11.8 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.57 kB
build/date/index.min.js 40.4 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-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 34.5 kB
build/edit-post/style-rtl.css 7.5 kB
build/edit-post/style.css 7.5 kB
build/edit-site/style-rtl.css 10 kB
build/edit-site/style.css 10 kB
build/edit-widgets/index.min.js 16.9 kB
build/edit-widgets/style-rtl.css 4.52 kB
build/edit-widgets/style.css 4.52 kB
build/editor/index.min.js 45.5 kB
build/editor/style-rtl.css 3.54 kB
build/editor/style.css 3.53 kB
build/element/index.min.js 4.93 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.26 kB
build/format-library/style-rtl.css 557 B
build/format-library/style.css 556 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.92 kB
build/list-reusable-blocks/index.min.js 2.14 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.99 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.52 kB
build/private-apis/index.min.js 942 B
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 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.8 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.69 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.31 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@github-actions
Copy link

github-actions bot commented Jan 25, 2023

Flaky tests detected in 47a5430.
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/4136315129
📝 Reported issues:

@youknowriad
Copy link
Contributor

Hi @afercia it looks like this PR contains two separate fixes. One for constrained tabbing and one for modals? Does it make sense to split these into two smaller PRs?

While the change for the constrained tabbing behavior seems quiet straightforward, I'd like to understand more the changes for the modal component.

@afercia
Copy link
Contributor Author

afercia commented Jan 26, 2023

Hi @youknowriad Sure I might split this fix into two smaller PRs but I'm not sure it would make much sense. While this PR touches two components, it actually fixes one feature: constraining tabbing.
If I split, the a11y tests will still fail, either with Safari or Firefox.
If you really have a strong preference for splitting, I have no objections though.
Glad to help clarify the changes, if needed.

@afercia
Copy link
Contributor Author

afercia commented Jan 27, 2023

Tests keep failing for unrelated reasons, mostly timeouts or crashes e.g. page.reload: Navigation failed because page crashed!. Super annoying. Will rebase, not that I hope that will solve anything.

@afercia afercia force-pushed the fix/constrained-tabbing-safari-firefox-failures branch 2 times, most recently from 5d57d28 to 3e35ac3 Compare January 30, 2023 10:24
@youknowriad
Copy link
Contributor

Sorry for the delay. If these are part of the same issue, it's fine to keep them together.

I have some questions here:

  • The "scrollable" related fix seems to only be applied to Modal component. What happens to the other places where we use useConstrainedTabbing (Thinking about popovers, ...). Isn't it better to apply that fix as a hook within useDialog or something like that, so that way it applies everywhere?

  • Why did you chose to apply "Firefox"'s behavior to all the other browsers instead of doing the opposite? Was that the simplest option?

@afercia
Copy link
Contributor Author

afercia commented Feb 1, 2023

@youknowriad thanks for your feedback. I'll try to do my best to answer your question.

The 'scrollable' fix will need to be applied wherever there is a scrollable element. That's not limited to the Modal or popover components. So I'm not sure useDialog would be a good place for this kind of fix. I plan to improve the existing Scrollable component in #45809 and incorporate the accessibility improvements there. Once that is done, the improved Scrollable component should be used within the Modal to replace this temporary fix and everywhere there is a scrollable element. For now, this PR aims to fix the 'scrollable' thing within the Modal because it breaks constrained tabbing.

Why did you chose to apply "Firefox"'s behavior to all the other browsers instead of doing the opposite?

Scrollable elements need to be keyboard accessible to solve cases like #41500. To do that, the scrollable element needs to be focusable in the first place. Firefox is the only browser that natively makes scrollable elements focusable. It does that only when there's an actual content overflow. You can test native browsers behavior on this codepen.
Other browsers don't make scrollable elements focusable so they're not keyboard accessible. With these browsers it's not possible to scroll a scrollable element with a keyboard, unless it contains focusable elements. The recommended technique standardizes the Firefox accessible behavior across all browsers. This PR makes sure that this technique is applied 'dynamically' as in: only when there's an actual content overflow. 'Doing the opposite' wold mean making all scrollable elements not focusable in all browsers, so that they would be not operable with a keyboard in all browsers.

__( 'Scrollable section' )
: undefined
}
tabIndex={ hasScrollableContent ? 0 : undefined }
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think we can extract all this logic into a hook const { ref, props } = useScrollable();

and just basically apply the "ref" and "props" to the element that is supposed to be scrollable? I think it might bring some clarity to the code here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, not sure why we need childrenContainerRef can't we just check the height of the scrollable itself (or at least its children) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The scrollable element has a fixed height,
The height of the content (the children) determines the actual content overflow, when it's greater than the scrollable height.
There may be multipole children though. Not sure how to calculate eh height of multiple children that could also be dynamically rendered. Seems to me the simplest option is to check for the height of an additional container.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think we can extract all this logic into a hook

I'm all for better abstraction and improvements. I'd prefer to do that when enhancing the Scrollable component though. See #45809

@aristath
Copy link
Member

aristath commented Feb 8, 2023

This is a bugfix and as such, it looks good to me.
I agree with @youknowriad that it should be done in a hook. However, I think that perhaps the abstraction should probably be done in a follow-up PR? This way we can unblock this one, fix the bug, and continue with the abstraction separately.

@@ -65,6 +67,7 @@ function UnforwardedModal(
onKeyDown,
isFullScreen = false,
__experimentalHideHeader = false,
scrollableContentLabel,
Copy link
Contributor

Choose a reason for hiding this comment

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

This prop is the only API change in this PR. I'm fine with this PR if we don't add maintenance burden for us like that.

So in the sense, I suggested the refactor to improve the code quality a bit and clarify how this works but I'm fine shipping this as is if we only focus on the bug fix without new APIs...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok fair enough. Will remove it and keep the default aria-label={ __( 'Scrollable section' ) }

@afercia afercia force-pushed the fix/constrained-tabbing-safari-firefox-failures branch from 74b3b9a to 04b9c37 Compare February 9, 2023 15:50
Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

code is good to ship 👍 Might be good to get another a11y check though. @alexstine

Copy link
Member

@kevin940726 kevin940726 left a comment

Choose a reason for hiding this comment

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

Test looks good 👍 . Just a small question there.

test/e2e/specs/editor/various/a11y.spec.js Show resolved Hide resolved
@afercia
Copy link
Contributor Author

afercia commented Feb 10, 2023

Thanks everyone for the feedback and review.
Happy to see the tests pass with chromium, firefox, and webkit.
Everything is green but I'll wait a couple days to see if @alexstine has time for one more a11y check.

I commented on #45809 reporting the findings from this PR and the suggestion to craft a new hook. It will need to wait for #41001 anyways.

@alexstine
Copy link
Contributor

I do not think I can really add much to this PR. I trust your judgement @afercia . Thanks.

@afercia
Copy link
Contributor Author

afercia commented Feb 14, 2023

Thanks. Merging 🎉

@afercia afercia merged commit 6e7ddd6 into trunk Feb 14, 2023
@afercia afercia deleted the fix/constrained-tabbing-safari-firefox-failures branch February 14, 2023 07:57
@github-actions github-actions bot added this to the Gutenberg 15.2 milestone Feb 14, 2023
mmtr added a commit to Automattic/wp-calypso that referenced this pull request Apr 28, 2023
As of [Gutenberg 15.2](WordPress/gutenberg#47426), the `Modal` component no longer renders the passed React nodes as direct children of `.components-modal__content`, effectively breaking the flex layout used by our Limited Global Styles gating modal.

To fix that, we now use a wrapper with a custom class so we can build a flex layout without relying on how Gutenberg renders the `Modal` component.
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). [Package] Compose /packages/compose [Type] Bug An existing feature does not function as intended [Type] Regression Related to a regression in the latest release
Projects
None yet
6 participants