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 canvas iframe button accessibility and silent tab stops #59317

Merged
merged 3 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions packages/block-editor/src/components/iframe/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ function Iframe( {
shouldZoom = false,
readonly,
forwardedRef: ref,
title = __( 'Editor canvas' ),
...props
} ) {
const { resolvedAssets, isPreviewMode, isZoomOutMode } = useSelect(
Expand Down Expand Up @@ -283,9 +284,13 @@ function Iframe( {
}
}, [ scale, frameSize, marginFromScaling, iframeDocument ] );

// Make sure to not render the before and after focusable div elements in view
// mode. They're only needed to capture focus in edit mode.
const shouldRenderFocusCaptureElements = tabIndex >= 0 && ! isPreviewMode;

return (
<>
{ tabIndex >= 0 && before }
{ shouldRenderFocusCaptureElements && before }
{ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */ }
<iframe
{ ...props }
Expand All @@ -301,7 +306,7 @@ function Iframe( {
// mode. Also preload the styles to avoid a flash of unstyled
// content.
src={ src }
title={ __( 'Editor canvas' ) }
title={ title }
onKeyDown={ ( event ) => {
if ( props.onKeyDown ) {
props.onKeyDown( event );
Expand Down Expand Up @@ -346,7 +351,7 @@ function Iframe( {
iframeDocument.documentElement
) }
</iframe>
{ tabIndex >= 0 && after }
{ shouldRenderFocusCaptureElements && after }
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ function EditorCanvas( { enableResizing, settings, children, ...props } ) {
}
}, [ canvasMode ] );

const viewModeProps = {
'aria-label': __( 'Editor Canvas' ),
// In view mode, make the canvas iframe be perceived and behave as a button
// to switch to edit mode, with a meaningful label and no title attribute.
const viewModeIframeProps = {
'aria-label': __( 'Edit' ),
title: null,
role: 'button',
tabIndex: 0,
onFocus: () => setIsFocused( true ),
Expand Down Expand Up @@ -115,7 +118,7 @@ function EditorCanvas( { enableResizing, settings, children, ...props } ) {
}
),
...props,
...( canvasMode === 'view' ? viewModeProps : {} ),
...( canvasMode === 'view' ? viewModeIframeProps : {} ),
} }
>
{ children }
Expand Down
22 changes: 18 additions & 4 deletions test/e2e/specs/site-editor/navigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,26 @@ test.describe( 'Site editor navigation', () => {
page.getByRole( 'button', { name: 'Pages' } )
).toBeFocused();

// Test: Can navigate into the iframe using the keyboard
await editorNavigationUtils.tabToLabel( 'Editor Canvas' );
const editorCanvasButton = page.getByRole( 'button', {
name: 'Editor Canvas',
// Navigate to the Saved button first, as it precedes the editor iframe.
await editorNavigationUtils.tabToLabel( 'Saved' );
const savedButton = page.getByRole( 'button', {
name: 'Saved',
} );
await expect( savedButton ).toBeFocused();

// Test: Can navigate into the iframe using the keyboard.
// At this point the iframe has an ARIA role=button and it's labeled 'Edit'.
await editorNavigationUtils.tabToLabel( 'Edit' );

// Make sure to get the iframe with role=button.
const editorCanvasRegion = page.getByRole( 'region', {
name: 'Editor content',
} );
const editorCanvasButton = editorCanvasRegion.getByRole( 'button', {
name: 'Edit',
} );
await expect( editorCanvasButton ).toBeFocused();

// Enter into the site editor frame
await pageUtils.pressKeys( 'Enter' );
// Focus should be on the iframe without the button role
Expand Down
Loading