Open Bug 1615852 Opened 6 months ago Updated 3 months ago

broken `<br>` workaround in `<div contenteditable="true">` with bad side effects (also affects Google Sheets)

Categories

(Core :: DOM: Editor, defect, P3)

72 Branch
defect

Tracking

()

Tracking Status
firefox75 --- affected
firefox76 --- affected

People

(Reporter: pavlix, Unassigned)

References

(Depends on 1 open bug)

Details

Attachments

(1 file)

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0

Steps to reproduce:

Firefox adds an unexpected <br> to an editable <div> while editing the content. It does so when you delete the content of an editable and the spurious <br> stays even when you add new content.

  1. Create an HTML document that contains a <div> element with contenteditable attribute set true.

  2. Edit the <div> and add some text.

  3. Delete all the text using a backspace.

  4. Now add some text again.

  5. Check the contents of the <div> using DOM inspector.

Note: Don't add any newlines when testing for the spurious <br> element using the test above. However, when finished with this scenario, please try also experimenting with multiple lines. Firefox adds <div> subelements and even things like <div><br></div>. There seems to be a whole class of bugs related to editable content.

Actual results:

The contents of the <div> is your new text and an additional <br> element. This causes issues in Google Sheets and might be a source of many issues in various other web applications.

Expected results:

The contents of the <div> should only be your new text.

You can also use the following code (e.g. in a local HTML file) to reproduce the issue and discover related issues.

<!DOCTYPE html>
<html>
<head>
    <style>
        #source { width: 10em; background-color: lightgreen; }
        #target { margin-top: 1em; background-color: lightgrey; }
    </style>
</head>
<body>
    <div id="source" contenteditable="true">xxx</div>
    <div id="target"></div>

    <script>
        source = document.getElementById("source");
        target = document.getElementById("target");

        function display() {
            target.innerText = source.innerHTML;
        }

        source.addEventListener("input", display);
        display();
    </script>
</body>
</html>

With this code I observe and reliably reproduce the bug as desribed in the bug report. I also observe unusual behavior (as suggested in the note) when adding new lines in the editable content. Then it creates new inner <div> elements and then backspace can delete everything meaning that in one scenario an empty editable innerHTML becomes <br> and in another scenario it actually becomes empty.

If the <br> was meant as a sort of a workaround for layout/accessibility issues, then the behavior should really be:

  1. Consistent. An empty cell should always have the same content.
  2. Correct. An empty cell reports no content to any Javascript that wants to access it.
  3. Accessible. An empty cell should not disappear from the user.

A similar bug was reported in the past and discussed in fora:

In the past the issue was treated in relation to Google Sheets but I believe it is now clear that the behavior of contenteditable divs is buggy. I was asked to start a new bug report and here it is.

Bugbug thinks this bug should belong to this component, but please revert this change in case of error.

Component: Untriaged → DOM: Editor
Product: Firefox → Core
Attached file 1615852.html

I can reproduce this on the current nightly (20200216093058) on macOS -- attached is the testcase from the reporter with steps to reproduce inlined.

This is probably a duplicate (though with a specific STR) of bug 503838. See discussion in bug 1573801 comment 12 and onward.

The Google issue is tracked in bug 1605018.

Status: UNCONFIRMED → NEW
Ever confirmed: true
Priority: -- → P3

Additional experiments and results. Someone in #1573801 mentioned that the bug is about HTML contenteditable.

  1. Load the above document.

xxx

  1. Put the carret after xxx and hit Backspace thrice.

<br> (the workaround)

  1. Put back xxx.

xxx<br> (looks good in my case but becomes xxx\n<br> in Google Sheets)

  1. Hit Enter.

<div>xxx</div><div><br></div> (does this make sense?)

  1. Hit Backspace.

<div>xxx</div> (inconsistent, <br> is lost now)

  1. Hit Backspace thrice.

<div><br></div> (inconsistent, <br> is now back but enclosed in divs)

  1. Hit Backspace.

`` (<br> is now lost and the workaround failed completely, layout is of course broken)

  1. Type xxx.

xxx (just for completeness, you are now back to the initial state)

Also, if I change the source, so that I start with an HTML <p> element, it degrades easily to the original case.

Additional code needed:

    <button onclick="source.innerHTML = 'xxx'; display()">Reset (noparagraph)</button>
    <button onclick="source.innerHTML = '<p>xxx</p>'; display()">Reset (paragraph)</button>
  1. Load the document and click Reset (paragraph).

<p>xxx</p>

  1. Hit Backspace thrice.

<p><br></p> (the workaround)

  1. Hit Backspace.

`` (workaround lost, layout broken, paragraph editing lost)

  1. Type xxx.

xxx (parapraph editing lost)

Honestly, I don't even understand what was the intended behavior. Why do we need to ad <div>s rather than <br> in the non-paragraph example? If that was supposed to be a plaintext variant, why the <div>s? If the latter was supposed to be an HTML variant, why does it so easily degrade to the former?

Summary: spurious `<br>` in `<div contenteditable="true">` (also affects Google Sheets) → broken `<br>` workaround in `<div contenteditable="true">` with bad side effects (also affects Google Sheets)
No longer blocks: contenteditable
Depends on: 503838
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.