Gutenberg: Introduce a way to manage focus on the RichText editor

Created on 10 Sep 2018  路  19Comments  路  Source: WordPress/gutenberg

See discussion on Slack: https://wordpress.slack.com/archives/C02QB2JS7/p1536570671000100

In 4.0 the RichText onSetup prop will be deprecated and changed to unstableOnSetup. To my understanding, unstableOnSetup won't be removed so soon, see https://github.com/WordPress/gutenberg/pull/9106, because it's still necessary in current implementations of core blocks.

However, in the future there will still be the need to access the editor instance. Simple use case: managing focus. Imagine a custom block that uses one or more RichText components and needs to manage focus programmatically depending on specific workflows.

As mentioned in the Slack discussion, one option could be introducing a focus function to the RichText component. Definitely not my area of expertise, there are probably other options and considerations to explore. /Cc @iseulde @aduth

Accessibility (a11y) [Feature] Block API [Feature] Rich Text [Feature] Writing Flow [Package] Editor

Most helpful comment

Update: current state of the RichText component with regards to focus management after one year this issue was created:

  • unstableOnSetup was removed
  • setFocusedElement is now deprecated, see https://github.com/WordPress/gutenberg/pull/17421 and the recommended alternative is selection state from the block editor store
  • isSelected is now __unstableIsSelected, not sure how this is impacting / will impact the ability to manage focus

To recap the nature of this issue: seems to me all these changes fit only with the internal needs of Gutenberg. They don't take into consideration custom usages of RichText outside of the Gutenberg ones. Instead, plugins may need to implement their own focus management mechanisms.

Consider for example a block that uses multiple RichText components like the one below: each highlighted area is a RichText:

Screenshot 2019-09-13 at 12 08 02

One year ago, managing focus within such a block was pretty simple. Unfortunately, all the changes in the last year made it more and more challenging. At the point that providing basic keyboard accessibility is now very hard.

To me, it appears clear that Gutenberg should provide a mechanism to manage focus on the RichText instances within a block. Gutenberg removed features that made this kind of focus management possible: now, it's a Gutenberg responsibility to provide equivalent features.

All 19 comments

There are internal mechanisms with a block's context including isSelected and setFocusedElement which serve a purpose of coordinating multiple RichText in the same block. As best I can tell, they were designed to be used internal to the RichText component itself. I don't recall if it was undesirable or even possible to surface this up as an option to the block implementer.

Adding a focus function to the component interface seems reasonable enough. The main caveat is that it would be an imperative statement in its usage, vs. traditional React declarative / state-driven representation. Given the intention of focus changes to be a one-off action, this seems okay.

Related: Maybe worth noting that there is an unstableOnFocus _event handler_ which is used by a few core blocks, maybe complementary (and thus desirable to "stabilize") as part of an introduction of a focus function. Part of its prior marking as being unstable was the desire for it to not be passing the TinyMCE-specific event object as an argument.

Related: #6419

Maybe onSelect?

Additionally there's no way currently to set the focus at the end of the field.

I think this needs to be addressed before API freeze. I tried to make a block with multiple RichText fields and it is impossible to manage focus, even with unstableOnFocus. Passing isSelected={ true } does nothing to focus the field if requested.

Plus we are still using unstableOnFocus in some blocks.

Imagine a custom block that uses one or more RichText components and needs to manage focus programmatically depending on specific workflows.

I tried to make a block with multiple RichText fields and it is impossible to manage focus

The use-cases here are quite vague, or I'm not sufficiently imaginative. What is such a block trying to achieve with programmatically managing focus?

E.g. When you have multiple RichText fields in a block and you'd like to manage split and merge behaviour. Currently this is all possible, except for setting focus to the correct field. The block in question I was working on is the list blocks (with multiple RichText fields), but I can imaging this being useful for many kinds of blocks with Rich input fields.

At the very least I would like to see our own blocks not using unstableOnFocus.

Or maybe it should be kept (call on contentEditable focus for a stable result) and be renamed to e.g. onSelect which could go together with isSelected to set focus on the field.

This could also be revised as part of the focus setting we do currently in compontentDidUpdate, which is not really the greatest logic we have in RichText. :/

Related: #6419

I tried to use setFocusedElement where we currently use unstableOnFocus in the table block, but that didn't seem to work. Cc @gziolo.

I tried to use setFocusedElement where we currently use unstableOnFocus in the table block, but that didn't seem to work.

Yes, it was a quite complex use case. I need to refresh my memory to figure out what was blocking us from using setFocusedElement.

This is my previous attempt #6871 to fix it without using onFocus prop which was renamed later to unstableOnFocus as we decided to avoid landing this PR. It still needs some tinkering how to make it work in a more automated way. I think the biggest blocker was mentioned by @youknowriad in https://github.com/WordPress/gutenberg/pull/6871#issuecomment-392895193:

The issue is that sometimes RichText loses the focus but we still want to keep it selected. (Link modal, toolbar buttons), It's probably doable but not simple because of the fact that popovers show outside the RichText's node.

Quoting from the duplicate issue #12587

Looks like with the removal of unstableOnSetup in https://github.com/WordPress/gutenberg/pull/10744 there isn't a built-in way to manage focus on the RichText editable area any longer.

Managing focus is essential in some flows, especially for custom block types with multiple RichText instances. While the removal of unstableOnSetup was expected to happen without notice, a new, alternative, method was expected as well.

Other editors expose a focus method: for example, Draft.js explains very well why this is needed, see https://draftjs.org/docs/advanced-topics-managing-focus

Discussed a bit this issue with our technical team at Yoast and we'd tend to think that also all use-cases that were offered by a reference to TinyMCE would need to be offered by the wrapper, RichText in this case.

I think this is essential functionality for an editable field component, which RichText is. I understand the choice to not expose the TinyMCE instance, but focusing an editable field is core functionality.

馃憢 , with https://github.com/WordPress/gutenberg/pull/14640 the selection logic has received a significant update, including how components (RichText in particular) get focused. I wonder if this ticket needs some updating so we better understand the current state of things. Wdyt @ellatrix ?

Does this relate to the situation where a RichText component within a block receives focus when a block is inserted? I'd love to have a flag to prevent that behavior (so the user has to explicitly select the RichText area to focus it) but I'm not sure if that counts as part of this issue, or in another issue :)

Could look essentially like focusOnInsert={ false }, defaulting to true to keep the current behavior.

No this is unrelated. It's about introducing a way to set focus _programmatically_ on the contenteditable. Currently, there's no way to get a block editor (TinyMCE) instance, see original description and linked references.

A related issue for the table block is potentially https://github.com/WordPress/gutenberg/issues/14904. I can think of a workaround using event handlers and element.focus(), but it'd be great if there was a way to forward focus from the surrounding td to the child RichText.

At some point I also want to introduce the ability to navigate the table block using arrow keys, which might be another use case, but also something that could use element.focus() as an intermediate step.

Update: current state of the RichText component with regards to focus management after one year this issue was created:

  • unstableOnSetup was removed
  • setFocusedElement is now deprecated, see https://github.com/WordPress/gutenberg/pull/17421 and the recommended alternative is selection state from the block editor store
  • isSelected is now __unstableIsSelected, not sure how this is impacting / will impact the ability to manage focus

To recap the nature of this issue: seems to me all these changes fit only with the internal needs of Gutenberg. They don't take into consideration custom usages of RichText outside of the Gutenberg ones. Instead, plugins may need to implement their own focus management mechanisms.

Consider for example a block that uses multiple RichText components like the one below: each highlighted area is a RichText:

Screenshot 2019-09-13 at 12 08 02

One year ago, managing focus within such a block was pretty simple. Unfortunately, all the changes in the last year made it more and more challenging. At the point that providing basic keyboard accessibility is now very hard.

To me, it appears clear that Gutenberg should provide a mechanism to manage focus on the RichText instances within a block. Gutenberg removed features that made this kind of focus management possible: now, it's a Gutenberg responsibility to provide equivalent features.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nylen picture nylen  路  3Comments

ellatrix picture ellatrix  路  3Comments

spocke picture spocke  路  3Comments

JohnPixle picture JohnPixle  路  3Comments

moorscode picture moorscode  路  3Comments