Problem/Motivation

The Canvas renders real component markup. When a slot holds markup its parent element cannot contain, the browser rewrites the page while parsing it, and the builder stops working.

Seen with a UI Suite Bootstrap Button placed in the label slot of another Button. A button cannot hold a button, so the parser closes the outer one early. The closing tags after it no longer match, and elements rendered after the panels fall out of the builder root, the contextual menu and the message stack among them.

Measured on a pattern preset builder:

  • The server HTML nests two buttons in the Canvas. The live DOM nests none: the inner button is a sibling of the outer one.
  • .display-builder__menu and .db-messages are children of .dialog-off-canvas-main-canvas, not of section.display-builder. On a builder without nested buttons both are inside it.

Consequences:

  • A contextual menu action leaves without node_id, parent_id and slot_id. menuAlterHtmxEvents() listens for htmx:configRequest on the builder root, which the menu is no longer in. The action answers "This change cannot be applied" since #3626659: Paste, duplicate and preset insert end in a server error when the target is full or gone, and a server error before it.
  • The Canvas no longer shows the tree: the inner button looks like a sibling of the outer one.
  • Right after the drop, before any reload, the swapped markup is parsed the same way and the Canvas looks wrong.

The way in is one click today: Duplicate on a root Button, #3627000: Duplicate from the contextual menu puts a root component inside its own first slot. Dropping a Button into a Button's slot by hand does the same.

Steps to reproduce

  1. With UI Suite Bootstrap, drop a Button at the root of a builder.
  2. Drop a second Button into its Label slot.
  3. Reload the page.
  4. Right-click a node and choose Duplicate: it is refused, and nothing on screen says why.

Proposed resolution

To decide. The options, which are not exclusive:

  • Keep the builder working whatever the Canvas holds. Render the menu, the message stack and the summary before the panels in display_builder.twig, so a misplaced closing tag cannot take them out of the root. Cheap, and it does not fix the Canvas.
  • Or make the menu listener independent of where the menu sits: listen on the document and match the builder by its ID.
  • Tell the user. After a render, compare the Canvas with the tree and flag a node whose DOM parent is not its tree parent, pointing to Scaffold, which draws cards instead of real markup.

Refusing the drop is not an option in general: the builder does not know which element a component renders its slot in.

Remaining tasks

  • Pick among the options above.
  • Check the other pairs the HTML parser rewrites: a link in a link, a form in a form, a block element in a paragraph.
  • A test that keeps the contextual menu working with a Button in a Button.

User interface changes

Depends on the option.

API changes

None.

Data model changes

None.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mogtofu33 created an issue. See original summary.

mogtofu33’s picture

Issue summary: View changes

mogtofu33’s picture

Assigned: mogtofu33 » Unassigned
Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • mogtofu33 committed a9ae244b on 1.0.x
    fix: #3627001 Dropzones and block wrappers are custom elements