Cypress: Cannot focus element inside content editable element

Created on 3 Nov 2018  路  10Comments  路  Source: cypress-io/cypress

Current behavior:

If I try to .get a content editable p element, I cannot use .focus() to focus it, since calling .focus on a DOM element inside a contenteditable will not give focus nor set document.activeElement

Desired behavior:

I should be able to focus content editable element to set cursor position to that element

Versions

Cypress: 3.1.1
OS: Linux Ubuntu 18.04

contenteditable native events

Most helpful comment

So typing works, but focus does not. For example, if you check this ProseMirror example if you focus on the content editable which is for example all text bold, you will see that the toolbar changes and detect that editor is focused and that content is bold. But if I do .focus() I do not get anything.

It does work if I create a selection manually:

    cy.window().then((window) => {
      cy.get('.editor p').then(($el) => {
        const el = $el.get(0);
        const range = window.document.createRange();
        range.setStart(el, 0);
        range.setEnd(el, 0);

        const selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
     });
   });

All 10 comments

I'm able to focus and type into a content editable paragraph with the following:

cy.get("p")
.focus()
.type("hello")

Do you have a code sample or any additional information that could help us debug?

So typing works, but focus does not. For example, if you check this ProseMirror example if you focus on the content editable which is for example all text bold, you will see that the toolbar changes and detect that editor is focused and that content is bold. But if I do .focus() I do not get anything.

It does work if I create a selection manually:

    cy.window().then((window) => {
      cy.get('.editor p').then(($el) => {
        const el = $el.get(0);
        const range = window.document.createRange();
        range.setStart(el, 0);
        range.setEnd(el, 0);

        const selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
     });
   });

Hey @mitar, the .focus() command is only used to fire the 'focus' event for an element, it is not intended to create a selection range/highlight text.

If you'd like to highlight text as you've shown above, that would require a branch new Cypress command. I'd suggest updating this issue to reflect that feature request if that's the case.

I mean, focus on content edible is this. From the user perspective. If I click on content editable as an user, it makes a selection in the browser.

So is Cypress API mimicking the user or the events? I thought high level calls like click, type and focus are more about user, and only trigger is about events? If I want focus event, then I can call trigger('focus'), no? But I want focus behavior, so I call focus?

@mitar focus does not imply selection. for example in the DOM API, for text inputs, we have .focus() and we have .select(). Focus simply places the cursor in the input, while .select() makes a selection on the existing text as well as giving focus (similar to tabbing into an input).
If you want to select arbitrary text inside a contenteditable, we do not yet offer such a fine-grained API, but are planning to. In the meantime, your current strategy is best practice

But in the context of content editable, when you click as user (not select) to focus, you are making a collapsed selection.

I think you should really decide if focus wants to be a high-level function which simulates what would happen if user clicks on a DOM element to focus the element. Or is just trigger('focus').

@mitar calling .focus() does in fact make a collapsed selection.
image

calling .focus() places the cursor at the very start of the contenteditable.

We do not cause a click side-effect because that would lead to a lot of confusion.

We are actually changing this API in the next iteration:

  • Currently, if you ask to .type() without having the element in focus, we issue a click (moving the cursor to the end of the text input)
  • In cypress-next, we will focus and move the cursor to the end without issuing a click

@mitar ah, I see what you mean now. Calling focus on an element _inside_ a contenteditable does not give that element focus, nor set document.activeElement

we still will be able to append text to it with .type(), but .focus() will not create a selection

@mitar I think .focus() should remain as is, but we should consider this when adding text selection API to cypress

The code for this is done in cypress-io/cypress#9066, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

Released in 6.0.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v6.0.0, please open a new issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

simonhaenisch picture simonhaenisch  路  3Comments

dkreft picture dkreft  路  3Comments

brian-mann picture brian-mann  路  3Comments

carloscheddar picture carloscheddar  路  3Comments

weskor picture weskor  路  3Comments