Skip to content

Nested editing hosts do not need to be wrapped in insertParagraph #490

Description

@gmta

When performing the action for insertParagraph, step 11 asks to check if the container is not editable:

If <var title="">container</var> is not <a href=
"#editable">editable</a> or not <a href=
"#in-the-same-editing-host">in the same editing host</a> as
<var title="">node</var> or is not a <a href=
"#single-line-container">single-line container</a>:

This is not how it currently works in both Chrome and Firefox for the following case:

<div contenteditable>foo <div contenteditable>bar</div></div>

If insertParagraph is run while a selection exists inside the inner editing host, a new container is created to wrap the contents in. This should not be necessary, and Chrome and Firefox both use the existing inner editing host as the container.

The behavior seems to be more accurately reflected by:

If the container is not editable and the container is either not an editing host, or its parent is neither editable nor an editing host, ...

An alternative approach could be to change the "is editing host" logic to exclude elements with contenteditable set to true or plaintextonly that are children of an editable node or an editing host, which is the approach I took for Ladybird.

Activity

  1. added
    Agenda+Agenda item to be inserted in the Editing TF meeting queue
    on Oct 9, 2025
  2. annevk commented on Oct 9, 2025

    @annevk
    Member
  3. annevk commented on Oct 9, 2025

    @annevk
    Member

    @gmta could you create a test case for your scenario? We tried to reproduce this during the meeting and got different results.

  4. gmta commented on Oct 17, 2025

    @gmta
    Author

    @gmta could you create a test case for your scenario? We tried to reproduce this during the meeting and got different results.

    This is similar to the test case I used to write the fix for Ladybird:

    <!DOCTYPE html>
    <div id="a" contenteditable>foo <div id="b" contenteditable>bar</div></div>
    <pre id="output"></pre>
    <script>
    getSelection().setBaseAndExtent(b.firstChild, 0, b.firstChild, 1);
    document.execCommand('insertParagraph');
    output.append(a.outerHTML);
    </script>

    FIrefox:

    <div id="a" contenteditable="">foo <div id="b" contenteditable=""><br></div><div contenteditable="">ar</div></div>

    Chrome and Safari:

    <div id="a" contenteditable="">foo <div id="b" contenteditable=""><br></div><div id="b" contenteditable="">ar</div></div>

    Ladybird (pre-fix):

    <div id="a" contenteditable="">foo <div id="b" contenteditable=""><div><br></div><div><div>ar</div></div></div></div>

    Ladybird (including ad-hoc change to "is editing host"):

    <div id="a" contenteditable="">foo <div id="b" contenteditable=""><br></div><div contenteditable="">ar</div></div>

    Note that this last output is identical to Firefox' output. Also note that Chrome and Safari seem to duplicate the id attribute, which arguably seems like worse behavior.

  5. self-assigned this
    on Oct 20, 2025
  6. masayuki-nakano commented on Oct 21, 2025

    @masayuki-nakano
    Collaborator

    I think that the editing host definition is wrong. The definition does not assume that contenteditable="true" and contenteditable="plaintext-only" are nested. I believe that it's not an editing host if an editable element parent is also editable.

  7. johanneswilm commented on Dec 11, 2025

    @johanneswilm
    Contributor

    TPAC 2025:

    Ollie: Postpone due to editor being in other meeting.

  8. added and removed
    Agenda+Agenda item to be inserted in the Editing TF meeting queue
    on Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions