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

Keyboard interaction: standardize the blocks behavior #2031

Closed
afercia opened this issue Jul 26, 2017 · 30 comments
Closed

Keyboard interaction: standardize the blocks behavior #2031

afercia opened this issue Jul 26, 2017 · 30 comments
Labels
[Feature] Blocks Overall functionality of blocks [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Priority] High Used to indicate top priority items that need quick attention

Comments

@afercia
Copy link
Contributor

afercia commented Jul 26, 2017

Splitting this out from #1516

See also:
Unexpected reverse-tab behaviour #1934
Image block keyboard focus and tab order #1829
Improve the block multi-selection and keyboard interaction #1308

Currently, the Tab/focus behavior across the blocks is inconsistent. Some blocks (e.g. text) have 2 focusable containers, while other blocks (e.g. image) have just one focusable container. This is particularly noticeable when tabbing backwards, see #1934 for more details.

screen shot 2017-07-26 at 11 05 37

On the first type of blocks (e.g. text), Gutenberg automatically moves focus from the outer container to the inner container (the one with contenteditable). On the second type of blocks, there's only one focusable container and users are forced to tab through all the toolbar controls.

This leads to an inconsistent experience for users and, I guess, to some complication codewise. Standardizing this behavior would improve usability and user experience. It would be great to also preserve quick navigation through blocks when tabbing.

What if all blocks had 2 focusable containers? This way, each container could have a different purpose, and expose different controls to users. However, at the same time there should be a mechanism to allow quickly tabbing through blocks with just one Tab press.

The outer container could be used for navigation through blocks, the inner container for editing the block.

On #1516 (comment), @jasmussen proposed a new flow to improve keyboard interaction and multiple selection that could be combined with two focusable containers:

  • tab highlights a block (same as cursor hover)
  • enter "clicks" it (block shows quick toolbar)
  • escape unselects it (showing hover again)
  • tab when "hovered" sets focus on a checkbox
  • my edit: at step 2, when "clicked", the blocks controls and content become tabbable

With some adjustments, this approach could serve both purposes. Interaction details still to lay out but I'd propose to give this some serious thinking 🙂

@afercia afercia added [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Feature] Blocks Overall functionality of blocks labels Jul 26, 2017
@ellatrix
Copy link
Member

See also #552 for approaches.

@BoardJames
Copy link

I believe to fix this we will need to do the following:

  • Make all focusable components tabIndex="-1" as we can't rely on browser to automatically create logical cycles (both TinyMCE and Textbox.io manage focus internally manually like this)
  • Setup code to handle focus manually
  • Setup shortcut keys to focus the toolbar of the current block (ALT + F10 is typical) but otherwise don't focus them on normal tabbing
  • Create a help page (with shortcut key to display) which lists keyboard shortcuts

Within a block I envisage focus working like this...

  • Press Alt+F10 to go to the block toolbar (yellow arrow)
  • Press tab to cycle to next toolbar group (red arrows)
  • Press shift+tab to cycle to previous toolbar group (red arrows reversed)
  • Press right arrow or down arrow to move to the next toolbar button within a group (blue arrows)
  • Press left arrow or up arrow to move to the previous toolbar button within a group (blue arrows reversed)
  • Press down arrow on a menu to open the menu
  • Press tab or down arrow to move to the next menu item
  • Press shift+tab or up arrow to move to the previous menu item
  • Press escape to close the menu
  • Press escape to leave the toolbar and return to the editor for the current block
  • Press tab to move to the next block (green arrow pointing down)
  • Press shift+tab to move back to the previous block (green arrow pointing up)
  • I believe that the arrows to move blocks up and down should not be in any focus cycle but should have a dedicated shortcut ( maybe ctrl+shift+up / ctrl+shift+down ?).

list-block-annotated
Key:
Green Arrow Down = Tab, Green Arrow Up = Shift+Tab, Yellow Arrow = Alt+F10, Red Arrow = Tab, Blue Arrow = Right Arrow Key

@BoardJames BoardJames self-assigned this Aug 7, 2017
@afercia
Copy link
Contributor Author

afercia commented Aug 7, 2017

Re:

Setup shortcut keys to focus the toolbar of the current block (ALT + F10 is typical) but otherwise don't focus them on normal tabbing

Yes! And we've also discussed a bit to keep ALT + F10 (which is suggested as an example in the ARIA Authoring Practices) but also use the new Cmd or Control suggested by @iseulde. See #552 (comment). Quoting myself 🙂

However, I've never got the reasoning behind that. Alt + F10 doesn't seem the most discoverable and easy to remember shortcut. I'd vote for keeping Alt + F10 for users that are used to that and introduce cmd/ctrl as a new, easier one.

Re: the toolbars. I'd recommend to keep them as simple as possible and adhere to the interaction model described in the ARIA Authoring Practices. See https://www.w3.org/TR/wai-aria-practices/#toolbar
Where the toolbar has just 1 tab stop. Everything inside a toolbar can be navigated with arrow keys only. The W3C example is very clear, I'd recommend to try it using only the keyboard: https://www.w3.org/TR/wai-aria-practices/examples/toolbar/toolbar.html

Worth noting a potential problem in Gutenberg is that what we see as a single toolbar, it's actually made of multiple toolbar components: multiple <ul> elements. Theoretically, this could be fixed with a massive usage of role="presentation" to "flatten" the elements hierarchy for assistive technologies but maybe the best option would be exploring a way to make the toolbars a single <ul>.
Quickly discussed this with @aduth a while ago, see https://wordpress.slack.com/archives/C02QB2JS7/p1500487546970091

@afercia
Copy link
Contributor Author

afercia commented Aug 7, 2017

Re: toolbars, see also #632

@BoardJames
Copy link

BoardJames commented Aug 8, 2017

I'm starting to implement some of my ideas in try/2031-manual-focus though it is early days and I have so far broken far more things than I have fixed. I will update when I've got something worthwhile to try out which I hope to have in the next few days.

So far I've been mostly removing things from the default tab cycle which does at least result in a lot quicker keyboard navigation. I can see that Embeds may be tricky to figure out because they add a lot of things to the default tab cycle which we probably don't want there.

@BoardJames
Copy link

I have a WIP pull request at #2392

@afercia afercia added the [Priority] High Used to indicate top priority items that need quick attention label Aug 29, 2017
@afercia
Copy link
Contributor Author

afercia commented Aug 29, 2017

Marking with the high priority label to indicate it's an a11y priority.

@afercia
Copy link
Contributor Author

afercia commented Oct 18, 2017

See also #2990

@jasmussen
Copy link
Contributor

jasmussen commented Oct 19, 2017

Extracting a little bit from #3016 which touches on this, and I'd like to add some mockups as well. See also #2983 (comment).

The high level goal with keyboard interactions is that everything should be keyboardable. That serves as an umbrella goal, where two sub-goals are:

  1. We shouldn't require an inordinate amount of tab key presses to get what you need
  2. It should be obvious to anyone who uses a mouse and keyboard how to set focus in a textbox, and just go on and type, without having to worry about "modes"

If we do it right, modes (as has been brought up by Andrea countless times) can help this. When using just the keyboard, you can quickly enter and exit modes, pick the block you want to edit and get going.

On the flipside, if we do this wrong, it's unobvious how to edit even basic text, and interactions like selecting across paragraphs or moving up and down using the arrow-keys becomes obtuse and encumbered by having to make sure we are in the right mode.

We want to avoid Vim, in other words.

To be clear, both the modes, and the selection enhancements have to happen for the whole picture to form.

Here's how it could work

You click "Add New" to write a post, same as you would any editor. You click the text field and start typing. You can select across paragraphs (see #3038), and you can arrow-key across paragraphs without losing your place (see #2990). You are in edit mode, and if you don't know what that is, it's fine.

You can also press Escape. This exits edit mode, and enters navigation mode, and highlights the block you were editing.

In navigation mode, the arrowkeys (or tab for forward, shift tab for backwards), advances the highlight. Press Enter when any block is highlighted to start editing that block, and set the caret in the first available text area, or focus on the first available button.

If you are in navigation mode (invoked with Escape), pressing Escape again takes you back to where you were. I.e. if you have the caret in text, press Escape, you highlight that block. Press Escape again, and you're back in text.

In navigation mode you can also hold shift and select downwards using arrow-keys, same as you can in text (pending #3038). In fact, the "multi select mode" is sort of the beginnings of navigation mode.

In navigation mode you can also press Space to select or unselect a block that has the highlight.

Navigation mode can also be entered by mouse-clicking any of the movers, or the ellipsis, or mouse-selecting across blocks to invoke multi select. All these three interactions select blocks, which happens in navigation mode.

Use cases

  • There are three paragraphs. You set the caret in the first, select downwards. Once you select text to the edge of the first paragraph, and press down again, you select at the block level. This enters navigation mode, and you now have the first two paragraphs selected. You can now use the direct shortcut to turn this into a list, or tab into the ellipsis to pick that option from the menu.
  • You wrote a post with paragraph, image, paragraph, image, paragraph, image, and decide that you'd rather have the three images be a gallery. Your caret is in the text. You press Escape to enter navigation mode, move the highlight to the first image using the arrowkeys, press Space to select it, move to the next image, and the last. You now have the 2nd, 4th and 6th blocks selected, and you tab into the ellipsis menu, pick "Turn into >" and pick "Gallery".
  • You just wrote 8 paragraphs, realize it's all crap and want to delete it. You press ⌘A to select all text in the paragraph you're in, you press ⌘A again to now select all blocks, and you press Delete or Backspace to remove it. Blank slate.
  • You wrote a big post with text, a gallery, some images, and a quote. You use the mouse to click on the first big image — this shows the quick toolbar (as you're still in edit mode), and you click the full-wide option. You then click the gallery and make it wide, and you right-float the quote. You never entered navigation mode.
  • You wrote a big post, same as above — text, gallery, some images and a quote. You press escape to enter navigation mode, up-arrow to the first big image, press Enter to edit it, press (or our enter quick toolbar meta key whatever it ends up being), arrow-key to full-wide, and pick it. You press Escape again to enter navigation mode, move down to the gallery, do the same dance and set it to wide.
  • You set focus on the title field, type a title, press Tab to move to the first block. You could've used the arrow key, or you could've pressed Enter, but you like tabbing, and because you're in edit mode, you just moved between text fields.

Pros and cons

In my head, the above feels like it gives us the best of both the keyboard and the mouse world. It feels like it's a modern selection paradigm for a block-based editor. It feels like it has a lot of benefits and flexibility.

The only concern I have, is whether it's discoverable or not, and whether you ever feel like the navigation mode becomes obtuse or cumbersome. I'd be worried if people accidentally entered navigation mode, and didn't know to press Enter or click a block with the mouse to get back out of it.

But perhaps that concern isn't valid, especially if Escape takes you right back to where you were? We already sort of have a navigation mode when you've multi selected blocks, and entering/exiting that mode doesn't feel like a problem.

One benefit of having a navigation mode is that you can easily select arbitrary blocks by navigating between them, "checking" them by pressing Space, and do operations on them. This is a nice interaction, and likely going to be welcomed by powerusers.

Can it be done?

The above is a suggestion, walking through the flow. It is a technically very difficult challenge, and so devs should chime in on the feasibility of the various interactions. Even if there's wide agreement that this flow is desirable, we should consider parsing microscopic action items into separate pieces and implement them one by one to make sure we do it right. "Focus hell" is a real thing, and I don't want to make it worse with the above.

CC: @aduth @iseulde @mtias @karmatosed @mcsf

@youknowriad
Copy link
Contributor

Trying to think the "Can it be done?" question.

I'd say mostly, yes. Here are the points that require some clarifications from my end:

  • You are in edit mode and you use arrows to navigate to other blocks

    • If the destination block doesn't have any "Editable" element, should we focus thee "Tabbable" elements (buttons/links)
    • What If the block doesn't have any tabbable element, should we focus the block container? Does this mean we're out of the edit mode? or should it be possible to focus the container even in edit mode? Which means we need to store this mode in state instead of guessing it from the focused element.
  • The second escape hit to move back to edit mode, might be harder to implement

  • When we use the inserter, we're automatically in edit mode?

@jasmussen
Copy link
Contributor

jasmussen commented Oct 19, 2017

You are in edit mode and you use arrows to navigate to other blocks
If the destination block doesn't have any "Editable" element, should we focus thee "Tabbable" elements (buttons/links)

Yes, I think that'd work great. Say you have a paragraph and an image placeholder, and you press down from the paragraph, it would be great if the first button of the placeholder (upload) gets focus.

What If the block doesn't have any tabbable element, should we focus the block container? Does this mean we're out of the edit mode? or should it be possible to focus the container even in edit mode?

Can we sort of do what we do now? For example if you have a paragraph and a separator, press down from the paragraph to put "focus" on the separaotr. Right now you see the movers and ellipsis, which lets you (in the future) use shortcuts to access these, or press Del to delete.

Does this mean we're out of the edit mode?

No, you don't exit edit mode ever, with only the arrow keys. I think it would be good if we could visually show where your "cursor" is, even if the cursor is hidden. For example if you arrow down into an image, you get the resizing handles. I'm sure I can think of a visual style to give to blocks like the Separator, to indicate where the "cursor" is.

The second escape hit to move back to edit mode, might be harder to implement

Even if it technically does the same as "Enter"? I know the caret position would probably reset, but perhaps that's fine?

When we use the inserter, we're automatically in edit mode?

Yes. I'd say we'd want for the user to almost always be in edit mode. The challenge here is making it clear how to enter navigation mode, and how to get back to edit mode again.

@youknowriad
Copy link
Contributor

youknowriad commented Oct 19, 2017

I know the caret position would probably reset, but perhaps that's fine?

Yes, that's the part that worries me, resetting the caret position

@jasmussen
Copy link
Contributor

Yes, that's the part that worries me, resetting the caret position

The worry is that you lose your place, correct? Or is there a technical concern?

@afercia
Copy link
Contributor Author

afercia commented Oct 19, 2017

I've just noticed that 58bd5f7 removed the tabindex and aria-label attributes from the outer block containers and moved them to the inner container editor-visual-editor__block-edit.

In navigation mode, when tabbing through the blocks, the blocks need to be focusable of course. They also need to be labeled with an aria-label otherwise assistive technologies users will land on a focusable element and hear just a resounding silence.

@youknowriad
Copy link
Contributor

The worry is that you lose your place, correct? Or is there a technical concern?

@jasmussen Yes yes, you lose your place, it's not easy to save "a position" and restore it back knowing the caret could be in a textarea, input, an editable, a button...

@afercia
Copy link
Contributor Author

afercia commented Oct 19, 2017

you don't exit edit mode ever, with only the arrow keys

I'd definitely agree 🙂 When in edit mode, navigation through contiguous editable blocks should work as close as possible to how a native textarea works. The challenge is about non-editable blocks.

What If the block doesn't have any tabbable element, should we focus the block container?

For example if you have a paragraph and a separator, press down from the paragraph to put "focus" on the separaotr.

As discussed during last Editor chat, maybe this would be easier if all the blocks always had 2 focusable containers: the outer one for navigation, the inner one for edit mode. For example, focusing the separator inner container should also allow to delete it with Backspace/Canc.

Maybe this would also help reinforce the 2 modes paradigm and standardize the blocks. Would probably also make developers life easier because all the blocks would have consistent behaviors.

To my understanding, editable blocks already have 2 focusable containers: the outer labeled one and the contenteditable one. In the screenshot below I've added some padding and border to highlight them:

screen shot 2017-10-19 at 12 50 30

However, there's the need of a container that wraps all the block including the mover, the ellipsis menu and other controls. How it worked before 58bd5f7 – see #2934 – was ideal for navigation mode and should probably be revisited.

Other blocks don't have the inner focusable container or they have mixed content of focusable and not focusable elements that would be difficult to handle. Maybe adding an inner focusable container to be used for Edit Mode and arrows navigation through blocks could help?

Navigation mode: Tabbing > focus is moved through the outer containers
Edit mode: using arrows > the inner containers are used for arrows navigation

Overall I really like the idea of having two modes. "Navigation mode" and "Edit mode" could also be visually communicated someway (see "The only concern I have, is whether it's discoverable or not") and also announced with speak() messages (to evaluate, just throwing out ideas).

I'd be worried if people accidentally entered navigation mode, and didn't know to press Enter or click a block with the mouse to get back out of it.

Mouse/touch users will click for sure. They click everything 🙂 Keyboard users would need to be informed about the two modes and documentation and communication is a very important point here. The paradigm "Enter" to edit and "Escape" to exit is pretty intuitive though.

@jasmussen
Copy link
Contributor

Yes yes, you lose your place, it's not easy to save "a position" and restore it back knowing the caret could be in a textarea, input, an editable, a button...

Right, I'm saying maybe it's okay to lose your place. But thinking about it, yeah maybe not. Perhaps we should go with Escape to enter navigation mode, Enter to go back to edit mode for now, and have only that.

@ellatrix
Copy link
Member

ellatrix commented Oct 20, 2017

However, there's the need of a container that wraps all the block including the mover, the ellipsis menu and other controls. How it worked before 58bd5f7 – see #2934 – was ideal for navigation mode and should probably be revisited.

See #2934 (comment) and #2934 (comment). Having nested focusable items seems like a bad thing?

@afercia
Copy link
Contributor Author

afercia commented Oct 20, 2017

As commented also on #2934 we should distinguish a bit. Things like:
<div tabindex="0"><button></button></div> are bad and I don't see a use for them.

Instead, a focusable container that is part of the layout is a bit different. For example, in WordPress #wpbody-content is focusable in all the admin screens and has tons of focusable controls inside.

We could also use tabindex="-1" so it is not tabbable, but is focusable programmatically and thus keyboard navigation through blocks should be scripted instead of native. Lots of possibilities but I don't see an accessibility or usability issue. The only concern maybe is about events: damn, they bubble :D but this is a common concern with all the Gutenberg components I guess and there'soften the need to stop propagation.

@ephox-mogran
Copy link
Contributor

What's the latest progress on this issue? @iseulde @mcsf @youknowriad @aduth @jasmussen @afercia. Has anyone started implementing the different modes on a branch anywhere?

@ephox-mogran
Copy link
Contributor

A few questions about selecting non-contiguous blocks. I'll start with mouse questions because they require fewer changes at the moment, and it will give me a chance to get my head around what is being requested and how to best implement it:

a) I I have made a multi-selection of continuous blocks, should Ctrl+Click on another block add that to the selection? If so, what would a Shift+Click do after that? Can we have multiple non-contiguous block selection ranges?

@afercia
Copy link
Contributor Author

afercia commented Oct 26, 2017

@ephox-mogran good questions :)
Personally, I'd think mouse selection should ideally work as it does natively.

If so, what would a Shift+Click do after that?

I'd say from the last clicked one to the currently clicked one, preserving the previous selection. See for example how selecting checkboxes in the WP list tables work, although that's jQuery and it's a not so known feature.

@ephox-mogran
Copy link
Contributor

So I'm going to try a slightly different approach here. Let me know what you think of it.

Basically, the idea is that I'll expand the redux state slightly to make focus a little more aware of components that are present in every block wrapper: move, toolbar (until it is moved), settings, the wrapper itself, and the blockEdit part. Therefore, instead of focus being a generic object that is block specific, focus will be:

focus: {
  target: block (wrapper) | toolbar | mover | settings | blockEdit,

  // Mostly, just used by blockEdit, but we might expand it later.
  options:  specific options for the target. 
}

This would give enough information to focus both the blocks in navigation (wrapper) and edit (blockEdit) mode, and would allow any of the hard-coded find selectors for focusing within blocks code to be removed. I'm going to experiment with this, and see how spaghetti-like it gets.

I'd like to keep mover and settings in there from the beginning, so that we could dispatch convenient actions to focus them immediately (based on keyboard shortcuts, perhaps), but I understand if you feel that's overkill for the time being, and we only need block and blockEdit in the short-term. The key aspect is that they shouldn't be difficult to add later if required.

@ephox-mogran
Copy link
Contributor

First part of an attempt at having a navigation mode and streamlining selected / focused state: #3195 . Far from finished. Did only include block and blockEdit targets for simplicity.

@ephox-mogran
Copy link
Contributor

To add multi-selection, we would just need to listen to the target of the keydown event (or check the focus state), and if it is the block container, then ignore the need to do any edge calculations and just expand selections. This would complement #3038.

Or should we just have a mode in the redux state. That might be the cleaner way of doing it? Or it might introduce redundancy that can get out of sync. Not sure which I would prefer ... probably having a mode. Thoughts? Or is this completely not the way that you wanted it done?

@afercia
Copy link
Contributor Author

afercia commented Oct 27, 2017

a little more aware of components that are present in every block wrapper: move, toolbar (until it is moved), settings, the wrapper itself, and the blockEdit part

Question: will custom components added by plugins be required to have those?

@ephox-mogran
Copy link
Contributor

I'm not all that familiar with the extensibility of the WordPress UI, unfortunately. Can plugins do that?

That's always the problem here. I feel there's a tension between handling focus in an orchestrated way (through redux state), and handling focus in a way that supports custom components that the application doesn't know about. We can just have two options like this PR, and assume that the rest of the components can be found by tabbing in the appropriate mode. So all they'd need is a tabindex the way that it currently works.

@afercia
Copy link
Contributor Author

afercia commented Jan 4, 2018

Quoting a couple points from the (now closed) issue with first accessibility recommendations #297, so they don't get lost:

  1. As I am thinking about this, it occurs to me that treating each content area as a modal once it has focus might be a good idea. The advantage is that it forces the context to be contained within the editable area.
  1. Make sure to undo all contenteditable attributes when done with a content area. Much like focus management.

Not saying they should be implemented at all costs, mainly because many things have changed in the meantime. However, in my opinion they support the idea of navigation mode / edit mode experimented in #3195

Especially the point 3. is interesting to me: I'd consider to try to constrain tabbing within a block while in edit mode. Arrows would always let me navigate content through blocks.

About the point 10, I'd leave that to the contenteditable experts here 🙂

@jasmussen
Copy link
Contributor

Edit mode is next on my mockups list. I know we've dabbled in the discussions, but I think some detailed mockups might help.

@afercia
Copy link
Contributor Author

afercia commented Mar 19, 2018

I'm going to close this issue and start a fresh new one to proceed with the navigation mode / edit mode experiment, see #3195. The accessibility team has identified a list of 10 high priority issues for version 1 and agreed with the Gutenberg team to mark them with the "merge proposal" milestone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Blocks Overall functionality of blocks [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Priority] High Used to indicate top priority items that need quick attention
Projects
None yet
Development

No branches or pull requests

6 participants