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

Cover placeholder: color palette not fully operable with keyboard #68639

Closed
2 of 6 tasks
afercia opened this issue Jan 13, 2025 · 10 comments · Fixed by #68662
Closed
2 of 6 tasks

Cover placeholder: color palette not fully operable with keyboard #68639

afercia opened this issue Jan 13, 2025 · 10 comments · Fixed by #68662
Assignees
Labels
[Block] Cover Affects the Cover Block - used to display content laid over a background image [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Package] Block library /packages/block-library [Package] Components /packages/components [Type] Bug An existing feature does not function as intended

Comments

@afercia
Copy link
Contributor

afercia commented Jan 13, 2025

Description

Discovered while working on #68602

The Cover block placeholder now shows a color palette users can use to set a background color:

Image

Navigating the color options with the keyboard isn't fully functional and at some point users may end up in a state where it is impossible to change the selected color option with the keyboard.

It appears this UI change hasn't been tested at all with keyboard, as the non-functional keyboard navigation is very clear and apparent. I would like to remind that any new UI should be tested for at least basic keyboard interaction before being merged and released.

Step-by-step reproduction instructions

  • Add a Cover block.
  • Navigate the block placeholder with the keyboard: Press the Tab key three times to move focus to the first color option.
  • At this point:
    • Tab: focus moves to the block settings panel
    • Right arrow: doesn't do anything
    • Left arrow: moves focus to the previous buttons in the placeholder
    • Down arrow: moves focus to the following color options, so this is the only keyboard navigation that works
    • Up arrow: moves focus to the wrapper block, so this doesn't work, although I guess it's the expected behavior for nested blocks

Screenshots, screen recording, code snippet

No response

Environment info

No response

Please confirm that you have searched existing issues in the repo.

  • Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

  • Yes

Please confirm which theme type you used for testing.

  • Block
  • Classic
  • Hybrid (e.g. classic with theme.json)
  • Not sure
@afercia afercia added [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Package] Block library /packages/block-library [Type] Bug An existing feature does not function as intended labels Jan 13, 2025
@afercia afercia self-assigned this Jan 13, 2025
@Mayank-Tripathi32
Copy link
Contributor

Hello, I would like to work on this issue.

@afercia
Copy link
Contributor Author

afercia commented Jan 13, 2025

The ColorPalette component uses CircularOptionPicker internally.

CircularOptionPicker has two variants, which are determined by the asButtons prop:

  • ButtonsCircularOptionPicker: the color options are buttons where keyboard navigation works with normal Tab key presses.
  • ListboxCircularOptionPicker: the color options are button elements with role=option within a role=listbox, where keyboard navigation works with arrow keys.

Normally, the color palette users ListboxCircularOptionPicker. This can be tested for example by selecting a Paragraph block and opening the color palette in the settings panel. In the color picker popover, the color options can be navigated with Right, Down, Left, Up arrow keys.

But...

when ListboxCircularOptionPicker is rendered within a block in the editor canvas, arrow keys navigation is borken, I guess because it conflicts with `WritingFlow.

In fact, to my understanding, arrow keys navigation within blocks is supposed ot navigate the nested blocks. Instead, other interactive controls like the color options should be naivgated with the Tab key.

A quick fix could be setting the asButtons prop to true to make Tab key navigation work.

@afercia
Copy link
Contributor Author

afercia commented Jan 13, 2025

One more thing to fix: I'm not sure I understand why the CircularOptionPicker.OptionGroup accepts a role prop.

When passed an aria-label or aria-labelledby, this role is set to group. The onlt use case I can think of is when multiple CircularOptionPicker.OptionGroup so that there are multiple groups of color options.

Worth considering the wrapper component may already have a listbox role or no role. Rather, I'd think the wrapper component should be either listbox or group when asButtons is true. Potential multiple groups within the wrapper would be either groups in a listbox or groups nested in a group.

Screenshot of the non-ideal rendered markup:

listbox:

Image

as buttons:

Image

@Mayank-Tripathi32
Copy link
Contributor

I noticed another behavior while reviewing the code and testing the block:

If you continue tabbing, it skips the upload button row in the cover block and jumps directly to the color picker last color.

Test.cover.block.asc.mp4

@afercia
Copy link
Contributor Author

afercia commented Jan 14, 2025

If you continue tabbing, it skips the upload button row in the cover block and jumps directly to the color picker last color.

That's because the color picker, when rendered as a Listbox with arrow keys navigation, implements the 'roving tabindex' keyboard interaction pattern where: 1) only one option is focusable at a time 2) the component 'remembers' the option that was focusable after tabbing away so when you tab back into it, that option is the one that receives initial focus.

However, this pattern should not be used inside a block in the blocks list becaue it conflicts with WritingFlow.

@afercia afercia added the [Block] Cover Affects the Cover Block - used to display content laid over a background image label Jan 14, 2025
@github-actions github-actions bot added the [Status] In Progress Tracking issues with work in progress label Jan 14, 2025
@afercia afercia added [Package] Components /packages/components and removed [Status] In Progress Tracking issues with work in progress labels Jan 14, 2025
@afercia
Copy link
Contributor Author

afercia commented Feb 7, 2025

While working on this, I also noticed that when CircularOptionPicker.OptionGroup is used 'standalone' like in the ColorPalette and in the GradientPicker components, it renders the buttons with a role="option" but the wrapper element has a role="group". That's wrong, it should be role="listbox".

Image

@afercia
Copy link
Contributor Author

afercia commented Feb 7, 2025

On a more general note, it appears that inside the editor canvas any UI that uses arrow keys navigation may conflict with WritingFlow. The conflict does not happen for UIs that are actually rendered outside the editor canvas e.g. the block toolbar menus. But it does happen of UIs inside the block placeholders or anywhere inside the canvas.

Cc @WordPress/gutenberg-core how can similar cases be prevented in the future? Would documentation, education and guidelines be enough? Not sure that's the case. Any thoughts?

@ciampo
Copy link
Contributor

ciampo commented Feb 7, 2025

While working on this, I also noticed that when CircularOptionPicker.OptionGroup is used 'standalone' like in the ColorPalette and in the GradientPicker components, it renders the buttons with a role="option" but the wrapper element has a role="group". That's wrong, it should be role="listbox".

(Cross-posting for extra visibility)

As I explain in this comment, it looks like there is a parent role="listbox" element (see code)

@afercia
Copy link
Contributor Author

afercia commented Feb 7, 2025

it looks like there is a parent role="listbox" element

Yes in that case. Not in other cases. This should be investigated becuase a structure like role=group > series of role=option without a parent role=listbox isn't valid.
To test:

  • Select a Paragraph block.
  • In the inspector, click Color > Text
  • Inspect the source of the color picker buttons.
  • Observe it's a series of buttons with role=option
  • Observe they are wrapped within an element with role=group
  • Observe there's no parent element with role=listbox, or at least I can't see one.

@ciampo
Copy link
Contributor

ciampo commented Feb 7, 2025

Yes in that case. Not in other cases. This should be investigated becuase a structure like role=group > series of role=option without a parent role=listbox isn't valid.

Agreed, it needs investigation to understand why this can happen in the first place, so that we can understand the best course of action to fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Cover Affects the Cover Block - used to display content laid over a background image [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Package] Block library /packages/block-library [Package] Components /packages/components [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants