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

[EuiCodeBlock] Improve accessibility of expandable code blocks #8195

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

mgadewoll
Copy link
Contributor

@mgadewoll mgadewoll commented Nov 28, 2024

Summary

closes #8175.

This PR aims to improve the accessibility of the EuiCodeBlock component, especially the expandable/fullscreen functionality.

Accessibility issues

  1. focusable code blocks did not have any semantic information (the code block is focusable when a height is set to provide scrolling via arrow keys - similar to a listbox pattern)
  2. entering fullscreen mode (expanded code block) did not announce the change to screen reader users
  3. closing the fullscreen mode via the collapse button did not return the focus to the toggle button

Changes

  1. focusable code blocks did not have any semantic information

<pre> elements don't have any semantic information (without adding a specific role) and hence also don't support aria-label to add additional semantic information directly. <code> elements don't accept aria-label and similar attributes either.

To address this a screen-reader only text was added inside the element to be read with the content. This includes the language prop of the code block to increase context.

// example for language="html"

html code block:
<p>
  <!-- Hello world -->
</p>
  1. entering fullscreen mode (expanded code block) did not announce the change to screen reader users

The fullscreen wrapper was not semantically marked and therefore did not provide any information about context change. The container is fullscreen and it has a focus trap, therefore it should be semantically defined as a dialog. Additionally this allows to apply an aria-label to the element, providing context on opening the dialog.

This will result in the following experience:

  • user opens dialog (expands code block)

screen reader output: "Expanded code bock, dialog"
depending on setting the screen reader might read the content of the dialog

  • the code block is focused

screen reader reads: html code block: <p> ...

  • ArrowUp/Down keys navigate the code block content line by line (screen reader browse modes)
  • Escape key anywhere in the dialog closes the dialog and returns the focus to the expand button
  • clicking the collapse button or pressing Enter key on it closes the dialog and returns the focus to the expand button
  1. closing the fullscreen mode via the collapse button did not return the focus to the toggle button

This PR adds a small change to the toggle functionality to ensure the focus is returned to the expand button when closing the fullscreen dialog.

Testing

NVDA

Screen.Recording.2024-11-28.at.15.37.22.mov

Screenshot 2024-11-28 at 15 37 58

JAWS

Screen.Recording.2024-11-28.at.15.35.41.mov

Screenshot 2024-11-28 at 15 36 31

QA

  • open the EuiCodeBlock story and set the overflowHeight control to 50 to reduce the height and enable the expandable code block

#generic

  • verify the code block can be navigated entirely by keyboard
  • verify there is no regression (Storybook, EUI docs) in functionality with production (Storybook, EUI docs)
  • verify that copying the code of a code block does not include the screen reader only label

#a11y

  • verify the component provides sufficient semantic context and focus management
    • verify the code block screen-reader only label is read, announcing it as code block of a specific type (depending on language prop)
    • verify the fullscreen element is a dialog and aria-label is read on opening (reading "Expanded code block, dialog")
    • verify dialog content can be navigated and closed with screen reader navigation and default keyboard navigation

General checklist

@mgadewoll mgadewoll marked this pull request as ready for review November 28, 2024 18:55
@mgadewoll mgadewoll requested a review from a team as a code owner November 28, 2024 18:55
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak left a comment

Choose a reason for hiding this comment

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

The changes look clean and the result is as expected, yay! 🥳 The code block is announced correctly both on focus and expansion.

I tried EuiCodeBlock with and without overflowHeight and isCopyable set.

2 questions:

  • Do you think it would be sensible to cover this by an automated a11y test?
  • Do we want this first approved by an accessibility contractor? Maybe it would be useful to make it a part of all (/most) accessibility tickets and have this check in the PR template?

Role and label:

Screenshot 2024-11-29 at 15 24 48

VoiceOver:

no overflowHeight set:

Screen.Recording.2024-11-29.at.15.10.26.mov

overflowHeight set to 1:

Screen.Recording.2024-11-29.at.15.11.01.mov

overflowHeight set to 1 and isCopyable to true:

Screen.Recording.2024-11-29.at.15.13.13.mov

Note: IMO the UX for copying the content could be improved. There's no information that the content has been copied on clicking the button.


I have 2 more suggestions and a question below 👇🏻

packages/eui/changelogs/upcoming/8195.md Outdated Show resolved Hide resolved
return showFullScreenButton ? (
isFullScreen ? (
// use delay to prevent label being updated in non-fullscreen state before fullscreen is opened
// otherwise this causes screen readers to read the collapse label before anything else (as the button was focused when opening)
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak Nov 29, 2024

Choose a reason for hiding this comment

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

non-blocking question: By "read (...) before anything else" we mean before the information that a dialog has opened?

Copy link
Contributor Author

@mgadewoll mgadewoll Nov 29, 2024

Choose a reason for hiding this comment

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

Yes, because how its build currently it uses the same button outside and inside the fullscreen dialog.
It seemed while the "Expand" button is focused and then opened and updated based on the isFullscreen condition it's already read out before the dialog had properly opened and applied focus to read the intended content instead.

Screenshot 2024-11-29 at 17 14 43

);
// pre tags don't accept aria-label without an
// appropriate role, we add a SR only text instead
const codeBlockLabelElement = (
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak Nov 29, 2024

Choose a reason for hiding this comment

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

praise: That's a clever workaround 👍🏻 it does generate some code because we need to strip the screen-reader-only content before copying but it's clean.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fyi, I'm reusing the screen-reader-only copy mechanics introduced in this PR

@mgadewoll
Copy link
Contributor Author

@L1nBra Could you have a look as well (ref original issue)?

@mgadewoll
Copy link
Contributor Author

mgadewoll commented Nov 29, 2024

@weronikaolejniczak

Do you think it would be sensible to cover this by an automated a11y test?

We could add a general test to cover keyboard navigation, yes. Beyond that we couldn't test much further as we can't assert screen reader output. (unless we implement something like guidepup)

Do we want this first approved by an accessibility contractor? Maybe it would be useful to make it a part of all (/most) accessibility tickets and have this check in the PR template?

Thanks for the reminder, I wanted to ping the contractor yesterday but forgot 😅

I'm not sure this needs to be a standard per se. 🤔 If we add it we should make it a) optional (default) and b) non-blocker.
I do think it's sensible to add the contractor if they raised the issue or if we have additional questions. But I think they might already have a lot on their plates and might not always be very responsive which could create bottlenecks. The baseline we can handle within the team I think.
But I'm open for opinions 🙂

@mgadewoll
Copy link
Contributor Author

@weronikaolejniczak Thanks for checking in VoiceOver! That's great to have an additional check. Just fyi, we need to keep in mind that VoiceOver is not the screen reader used by the majority of screen reader users. (there is no statistics but the regular Webaim screen reader surveys give us some idea)
Therefore we should always ensure to verify NVDA and/or JAWS on Windows mainly, while VoiceOver can be an additional check (that also means we optimize for Windows screen readers if the experience diverges) 🙂

@kibanamachine
Copy link

Preview staging links for this PR:

@elasticmachine
Copy link
Collaborator

💔 Build Failed

Failed CI Steps

History

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[EuiCodeBlock] Check and improve accessibility of expanding code blocks
4 participants