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

Image: Improve focus management in lightbox #55428

Merged
merged 9 commits into from
Oct 20, 2023
Merged

Conversation

artemiomorales
Copy link
Contributor

@artemiomorales artemiomorales commented Oct 17, 2023

What?

This PR makes the focus management more consistent in the image lightbox by removing the reference to event.pointerType and the differentiation in behavior when using a mouse versus a keyboard.

Why?

Addresses #55414 and improves on changes made in #55212.

Altogether, the previous approach was unreliable, so this PR aims to fix that.

How?

It removes the logic using event.pointerType, and instead...

  1. Makes sure focus is always set to the close button when the lightbox opens.
  2. Adds a tabindex of -1 to the image, which prevents the focus ring from erroneously showing around the close button when the lightbox is opened in Chrome and Firefox (the focus ring appears to always be visible in this case in desktop Safari, which appears to be the intended browser behavior).
  3. Stores a reference to the trigger button so that we can set focus to it when the lightbox closes.

Testing Instructions

  1. Add an image to a post
  2. Enable 'Expand on Click' in the image's block settings
  3. Publish and view the post
  4. Hover over the image and see that the cursor becomes a magnifying glass and that a button appears in the top right corner
  5. Click on the image or the button to open the lightbox

On keyboard, test that tabbing to the image will show the lightbox trigger button on focus and that pressing Enter or Spacebar opens the lightbox as expected.

While the lightbox is open, test that...

  1. Pressing Escape closes the lightbox
  2. Pressing Tab will move focus to the close button and trap it
  3. That pressing Enter or Spacebar while on the close button will close the lightbox
  4. Clicking on the modal or the close button will close the lightbox

When the lightbox closes, make sure focus is set on the lightbox trigger.

This commit removes the logic to set focus differently
based on event.pointerType and instead sets focus on the
dialog itself when the lightbox opens, and on the lightbox
trigger when the lightbox closes.
@github-actions
Copy link

github-actions bot commented Oct 17, 2023

Size Change: +1 B (0%)

Total Size: 1.66 MB

Filename Size Change
build/block-library/blocks/image/view.min.js 2.01 kB +1 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 964 B
build/annotations/index.min.js 2.71 kB
build/api-fetch/index.min.js 2.29 kB
build/autop/index.min.js 2.11 kB
build/blob/index.min.js 461 B
build/block-directory/index.min.js 7.25 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.28 kB
build/block-editor/content.css 4.27 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 219 kB
build/block-editor/style-rtl.css 15.6 kB
build/block-editor/style.css 15.6 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 104 B
build/block-library/blocks/avatar/style.css 104 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 633 B
build/block-library/blocks/button/style.css 632 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 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 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 421 B
build/block-library/blocks/columns/style.css 421 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 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
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 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 311 B
build/block-library/blocks/file/style.css 312 B
build/block-library/blocks/file/view.min.js 321 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 228 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 343 B
build/block-library/blocks/form-submission-notification/editor.css 342 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 452 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 957 B
build/block-library/blocks/gallery/editor.css 962 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 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 340 B
build/block-library/blocks/html/editor.css 341 B
build/block-library/blocks/image/editor-rtl.css 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/style-rtl.css 1.54 kB
build/block-library/blocks/image/style.css 1.54 kB
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 357 B
build/block-library/blocks/latest-comments/style.css 357 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 505 B
build/block-library/blocks/media-text/style.css 503 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 671 B
build/block-library/blocks/navigation-link/editor.css 672 B
build/block-library/blocks/navigation-link/style-rtl.css 103 B
build/block-library/blocks/navigation-link/style.css 103 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.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.26 kB
build/block-library/blocks/navigation/style.css 2.25 kB
build/block-library/blocks/navigation/view.min.js 1.07 kB
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 401 B
build/block-library/blocks/page-list/editor.css 401 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 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 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 508 B
build/block-library/blocks/post-comments-form/style.css 508 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 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 588 B
build/block-library/blocks/post-featured-image/editor.css 586 B
build/block-library/blocks/post-featured-image/style-rtl.css 345 B
build/block-library/blocks/post-featured-image/style.css 345 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 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 409 B
build/block-library/blocks/post-template/style.css 408 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-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 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 125 B
build/block-library/blocks/preformatted/style.css 125 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 335 B
build/block-library/blocks/pullquote/style.css 335 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 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 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/style-rtl.css 312 B
build/block-library/blocks/query/style.css 308 B
build/block-library/blocks/query/view.min.js 609 B
build/block-library/blocks/quote/style-rtl.css 222 B
build/block-library/blocks/quote/style.css 222 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 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 613 B
build/block-library/blocks/search/style.css 613 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 471 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 329 B
build/block-library/blocks/shortcode/editor.css 329 B
build/block-library/blocks/site-logo/editor-rtl.css 760 B
build/block-library/blocks/site-logo/editor.css 760 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 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 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.45 kB
build/block-library/blocks/social-links/style.css 1.45 kB
build/block-library/blocks/spacer/editor-rtl.css 359 B
build/block-library/blocks/spacer/editor.css 359 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 432 B
build/block-library/blocks/table/editor.css 432 B
build/block-library/blocks/table/style-rtl.css 646 B
build/block-library/blocks/table/style.css 645 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 403 B
build/block-library/blocks/template-part/editor.css 403 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/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 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 191 B
build/block-library/blocks/video/style.css 191 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 12.4 kB
build/block-library/editor.css 12.4 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 211 kB
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.4 kB
build/block-library/style.css 14.4 kB
build/block-library/theme-rtl.css 700 B
build/block-library/theme.css 705 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.5 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 947 B
build/commands/style.css 942 B
build/components/index.min.js 251 kB
build/components/style-rtl.css 11.9 kB
build/components/style.css 11.9 kB
build/compose/index.min.js 12.7 kB
build/core-commands/index.min.js 2.72 kB
build/core-data/index.min.js 71.7 kB
build/customize-widgets/index.min.js 12 kB
build/customize-widgets/style-rtl.css 1.51 kB
build/customize-widgets/style.css 1.5 kB
build/data-controls/index.min.js 651 B
build/data/index.min.js 8.87 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 462 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.68 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 35.7 kB
build/edit-post/style-rtl.css 7.88 kB
build/edit-post/style.css 7.88 kB
build/edit-site/index.min.js 206 kB
build/edit-site/style-rtl.css 14.3 kB
build/edit-site/style.css 14.3 kB
build/edit-widgets/index.min.js 17 kB
build/edit-widgets/style-rtl.css 4.85 kB
build/edit-widgets/style.css 4.84 kB
build/editor/index.min.js 45.9 kB
build/editor/style-rtl.css 3.58 kB
build/editor/style.css 3.58 kB
build/element/index.min.js 4.87 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.82 kB
build/format-library/style-rtl.css 577 B
build/format-library/style.css 577 B
build/hooks/index.min.js 1.57 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.61 kB
build/interactivity/index.min.js 11.4 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.76 kB
build/keycodes/index.min.js 1.9 kB
build/list-reusable-blocks/index.min.js 2.21 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.92 kB
build/notices/index.min.js 964 B
build/nux/index.min.js 2.01 kB
build/nux/style-rtl.css 775 B
build/nux/style.css 771 B
build/patterns/index.min.js 4.51 kB
build/patterns/style-rtl.css 518 B
build/patterns/style.css 517 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 1.85 kB
build/preferences/index.min.js 1.26 kB
build/primitives/index.min.js 994 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 988 B
build/react-i18n/index.min.js 631 B
build/react-refresh-entry/index.min.js 9.46 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.71 kB
build/reusable-blocks/index.min.js 2.73 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.2 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.96 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 1.98 kB
build/token-list/index.min.js 587 B
build/url/index.min.js 3.83 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 967 B
build/warning/index.min.js 259 B
build/widgets/index.min.js 7.18 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.03 kB

compressed-size-action

@artemiomorales
Copy link
Contributor Author

artemiomorales commented Oct 17, 2023

One issue with setting the focus on the dialog itself as recommended in #55414 is that this causes unexpected behavior in Safari. Usually it will cause VoiceOver to say that focus is on the close button, but it will not respond to an Enter keypress as expected. This may be because the close button is a child of the dialog, and having focus on the parent isn't supported.

I've recorded a video showing this behavior while casting the keystrokes to the screen:

Lightbox.Focus.Test.mp4

@github-actions
Copy link

github-actions bot commented Oct 17, 2023

Flaky tests detected in 6c1090a.
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/6578277725
📝 Reported issues:

@artemiomorales
Copy link
Contributor Author

artemiomorales commented Oct 17, 2023

I'm ready to get additional eyes on this and suggestions on how to improve the implementation. As of this writing, I've been unable to solve this issue in Safari while setting focus on the modal itself, i.e the element withrole=dialog.

@artemiomorales artemiomorales linked an issue Oct 17, 2023 that may be closed by this pull request
@artemiomorales artemiomorales added [Type] Bug An existing feature does not function as intended [Block] Image Affects the Image Block Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta labels Oct 17, 2023
It turns out that placing focus on the modal was causing
inconsistent behavior in Safari, so I've put the focus back
on the close button when the lightbox opens, which
performs predictably.

I've also added a tabindex to the image, which prevents
the focus ring from erroneously showing when opening the lightbox
with a mouse in Chrome and Firefox.
@artemiomorales
Copy link
Contributor Author

@afercia After looking at this with @SantosGuillamot, I don't think there's a way to set focus to the whole modal dialog without causing unexpected behavior (see video above).

So with that in mind, I've set the focus back to the close button, and I've also added a tabindex to the image, which at least prevents the focus ring from unnecessarily showing up around the close button on Chrome and Firefox when a mouse is used to open the lightbox (although it seems the focus ring is always visible in desktop Safari). The keyboard navigation seems to work in all cases and still displays the focus ring as expected.

I know you're not a fan of making the image itself clickable, but are there any technical drawbacks to adding a tabindex of -1 to the image or other issues this could cause?

@afercia
Copy link
Contributor

afercia commented Oct 19, 2023

@afercia After looking at this with @SantosGuillamot, I don't think there's a way to set focus to the whole modal dialog without causing unexpected behavior (see video above).

One issue with setting the focus on the dialog itself as recommended in #55414 is that this causes unexpected behavior in Safari. Usually it will cause VoiceOver to say that focus is on the close button, but it will not respond to an Enter keypress as expected. This may be because the close button is a child of the dialog, and having focus on the parent isn't supported.

@artemiomorales thanks for looking into this.
There's an incorrect assumption here that is probably a source of confusion. With Safari and VoiceOver, the correct way to press a button is by using Control+Option+Spacebar. Enter will only work if focus is on the button. But, actually, focus in on the dialog.
What happens here is specific to Safari and VoiveOver I think it is ok. When the modal dialog opens:

  • Keyboard focus is actually on the dialog.
  • The VoiceOver 'virtual cursor' is on the Close button instead.
  • Control+Option+Spacebar will close the dialog, as expected.
  • Enter will not close the dialog, because keyboard focus in on the dialog element.
  • If you press Tab, you will hear VoiceOver announces the Close button (again). This proves that focus was on the dialog and after pressing Tab goes to the button.
  • At this point, pressing Enter will work.

This is expected behavior.

There is one thing that behaves differently compared to the editor Mocal component though.
When the modal dialog opens, VOiceOver should not move virtual cursor to the Close button in the first place. This doesn't happen for example on the editor preferences modal dialog.
I have no idea why this different beheavior occurs but there are markup differences and on the Lightbox we are setting some aria-* attributes dynamically. That could have an impact. In any case, I'd recomment to focus the dialog. See ab653a4 that reinstates your first implementation and adds a negative tabindex to teh fialog to make it focusable. This is consistent with the Editor Modal component.

As an aside and out of curiosity, I spent some time trying to debug the Safari + VoiceOver behavior. I think it's something specific to Safari and the aria-modal attribute.

  • Comment out the ref.focus(); that sets focus on the dialog.
  • Test with only Safari, keep VoiceOver off.
  • Open the dialog with the keyboard Enter or Spacebar keys.
  • Observe that Safari sets focus on the Close button. This is weird because there is nothing that moves focus on the Close button. It appears to be a Safari thing. To me, it's a bug but I'm pretty sure the Apple fols would call it a "feature".
  • To confirm that focus in on the Close button, press Enter or Spacebar and observe the dialog closes.
  • Test with other browsers and observe that focus is not moved to the dialog, as expected, because we removed any focus management.
  • In the php file, remove the line to handle the aria-modal attribute data-wp-bind--aria-modal="selectors.core.image.ariaModal".
  • Test again with only Safari.
  • Open the dialog with the keyboard Enter or Spacebar keys.
  • Observe that this time focus is not moved to the dialog, as expected.

So it appears that Safari, when it sees an aria-modal attribute, now moves focus to the first focusable element within the element with aria-modal. To me, this is a bug. It may be related to recent work that browser vendors have been doing to align their implementations with the new focus steps for the HTML <dialog> element. Reference:
https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal
whatwg/html#4184

@afercia
Copy link
Contributor

afercia commented Oct 19, 2023

@aristath @carolinan and myself had a look at this and we think it's the smallest amount of changes we can introduce since we are in RC1. We recommend final review and testing with all major browsers.

@joedolson @alexstine I'd appreciate your thoughts and testing, especially with Windows screen readers. Thanks.

There are outstanding, broader, issues that would require some discussion and this is not the right time for that, as we are in RC1:

  • Absence of any visual hint that an image can be enlarged. In a page with many images, where only a few of them open in a Lightbox, users wan't have any way to understand the difference unless they hover or focus an image. we are not sure this is a good design and UX in the first place.
  • The image element is clickable and it opens the dialog. This is a non expected interaction and should be reconsidered. Windows screen readers will probably announce the image as 'clickable'.
  • The trigger button should enforce a minimum size of 24 by 24 pixels.
  • The Lightbox does not have feature parity with the Navigation, where users can change the appearance of the buttons.
  • The icon buttons don't visually expose their accessible name.

We agree all these points can't be addressed now. The should be addressed soon in the next release though.

Copy link
Contributor

@afercia afercia left a comment

Choose a reason for hiding this comment

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

Pending final review by @artemiomorales this LGTM

packages/block-library/src/image/index.php Outdated Show resolved Hide resolved
Copy link
Contributor

@alexstine alexstine left a comment

Choose a reason for hiding this comment

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

I don't have time to test this at the moment but the code changes look good until it can be revisited during next release.

Copy link
Contributor

@jameskoster jameskoster left a comment

Choose a reason for hiding this comment

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

It's working as advertised for me and is an improvement compared to trunk.

Copy link
Contributor

@michalczaplinski michalczaplinski left a comment

Choose a reason for hiding this comment

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

Tested it according to the instructions and it works as expected for me.

I don't have the a11y expertise to bring much nuance to the discussion but happy with the change since it's an incremental improvement over the current state of the Lightbox.

@artemiomorales
Copy link
Contributor Author

So it appears that Safari, when it sees an aria-modal attribute, now moves focus to the first focusable element within the element with aria-modal. To me, this is a bug. It may be related to recent work that browser vendors have been doing to align their implementations with the new focus steps for the HTML element. Reference:
https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal
whatwg/html#4184

@afercia Thank you for your detailed analysis and exploration. The approach we have now looks good to me. I've pushed a change removing the extra tabindex and will merge once the tests pass.

@afercia
Copy link
Contributor

afercia commented Oct 20, 2023

Thanks everyone for the PR, review, and feedback. From an a11y perspective, this looks good to me though I'd like to see it tested with WIndows screen readers.

We can investigate the different behavior of Safari / VoiceOver with the Lightbox modal dialog compared to the editor Modal component later in teh next release cycle.

@afercia
Copy link
Contributor

afercia commented Oct 20, 2023

I quickly tested on gutenberg.run with latest Firefox and NVDA.
As I was thinking, the image is announced as graphic clickable. Other than that, interaction and announcement with a screen reader look good to me. I think this looks good for RC 2. Screenshot:

Screenshot 2023-10-20 165058

Notice the doubled images within the dialog are both announced.

I will create a follow-up issue to evaluate improvements for the pending points.

Copy link
Contributor

@alexstine alexstine left a comment

Choose a reason for hiding this comment

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

@artemiomorales Tested on Windows with NVDA in Google Chrome and Firefox. This works well enough for now. Let's land it.

@artemiomorales artemiomorales merged commit fd8bdfe into trunk Oct 20, 2023
50 checks passed
@artemiomorales artemiomorales deleted the fix/lightbox-focus branch October 20, 2023 16:02
@github-actions github-actions bot added this to the Gutenberg 17.0 milestone Oct 20, 2023
@artemiomorales
Copy link
Contributor Author

Great, thank you all for the feedback and testing! This has been merged and will follow up on outstanding items in the next release cycle.

SiobhyB pushed a commit that referenced this pull request Oct 20, 2023
* Improve focus management

This commit removes the logic to set focus differently
based on event.pointerType and instead sets focus on the
dialog itself when the lightbox opens, and on the lightbox
trigger when the lightbox closes.

* Add delay before focusing when closing lightbox

* Put focus back on close button when opening lightbox

It turns out that placing focus on the modal was causing
inconsistent behavior in Safari, so I've put the focus back
on the close button when the lightbox opens, which
performs predictably.

I've also added a tabindex to the image, which prevents
the focus ring from erroneously showing when opening the lightbox
with a mouse in Chrome and Firefox.

* Move focus to the dialog when opening the lightbox.

* Fix SVG markup.

* Consistent indentation with spaces.

* Remove unnecessary tabindex

---------

Co-authored-by: Andrea Fercia <a.fercia@gmail.com>
@SiobhyB
Copy link
Contributor

SiobhyB commented Oct 20, 2023

Cherry-picked for inclusion in 6.4 in feefbe1.

@SiobhyB SiobhyB removed the Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Oct 20, 2023
SiobhyB pushed a commit that referenced this pull request Oct 23, 2023
* Focus submenu button when clicked (#55198)

* Focus element manually when open submenu on click

* Try using `tabindex="-1"`

* Use `tabindex="-1"` also in body when a submenu is opened

* Replace tabindex with event listener

* Explain the tabindex on <li>

* Don't store the element on hover to restore the focus later

* Improve explanations

* Add tests to cover webkit frontend menu interactions

Safari doesn't place focus on a clicked button as expected. These tests verify that when a submenu chevron button is clicked, focus is correctly placed on that button. It also verifies that the click on the body correctly closes any open submenus, which was failing in Safari.

* Focus clicked button on Safari

Combining the tabindex -1 on the parent li and focusing the button on Safari, and also checking that the relatedTarget is null inside the handleMenuFocusout seems to contain the focus within the menu to not fire the handleMenuFocusout as often, and still works to click on the body to close the menu.

* Added the document.addEventListener body click back in

Authored by Luis Herranz <luisherranz@gmail.com>. I'm just re-applying the change.

* Remove tab keypresses from webkit menu interaction tests

Tab keypreses on webkit playwright are really flakey (or it's something in our code that we haven't isolated) so I've split out the webkit tests to test everything I can without using a tab keypress.

* Use body click instead for consistency across environments

---------

Co-authored-by: Luis Herranz <luisherranz@gmail.com>
Co-authored-by: Jerry Jones <jones.jeremydavid@gmail.com>

* Make layout support compatible with enhanced pagination (#55416)

* Make layout supports compatible with enhanced pagination

* Use sanitize_title and add `layout` to the class name

* Update default fullscreen icon for lightbox trigger (#55463)

* Make duotone compatible with enhanced pagination (#55415)

* Patterns: fix capabilities settings for pattern categories (#55379)

Co-authored-by: Daniel Richards <daniel.richards@automattic.com>

* Revert "Patterns: fix capabilities settings for pattern categories (#55379)"

This reverts commit 6f83c92.

* Image block: wrap images with hrefs in an A tag (#55470)

* This commit sees what happens when we wrap the image element in an A tag in the editor.
This is to ensure any inherited styles from the link element, such as border color, apply to the image.

* Removing duplicate <a href /> wrapper
Adding disabled onClick and aria attribute

* Image: Improve focus management in lightbox (#55428)

* Improve focus management

This commit removes the logic to set focus differently
based on event.pointerType and instead sets focus on the
dialog itself when the lightbox opens, and on the lightbox
trigger when the lightbox closes.

* Add delay before focusing when closing lightbox

* Put focus back on close button when opening lightbox

It turns out that placing focus on the modal was causing
inconsistent behavior in Safari, so I've put the focus back
on the close button when the lightbox opens, which
performs predictably.

I've also added a tabindex to the image, which prevents
the focus ring from erroneously showing when opening the lightbox
with a mouse in Chrome and Firefox.

* Move focus to the dialog when opening the lightbox.

* Fix SVG markup.

* Consistent indentation with spaces.

* Remove unnecessary tabindex

---------

Co-authored-by: Andrea Fercia <a.fercia@gmail.com>

* Fix: - Update the title when using enhanced pagination

---------

Co-authored-by: Mario Santos <34552881+SantosGuillamot@users.noreply.github.com>
Co-authored-by: Luis Herranz <luisherranz@gmail.com>
Co-authored-by: Jerry Jones <jones.jeremydavid@gmail.com>
Co-authored-by: Artemio Morales <artemio.morales@a8c.com>
Co-authored-by: Glen Davies <glendaviesnz@users.noreply.github.com>
Co-authored-by: Daniel Richards <daniel.richards@automattic.com>
Co-authored-by: Ramon <ramonjd@users.noreply.github.com>
Co-authored-by: Andrea Fercia <a.fercia@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Image Affects the Image Block [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Image: fix focus management and accessibility of the Lightbox
6 participants