Problem/Motivation

Since #3562060: Render UI with admin theme the builder UI runs on the admin theme and the Canvas renders each component in its own declarative shadow DOM, on the front theme.
One shadow tree per component costs the Canvas fidelity:

  • a selector spanning a parent and a child component does not match (Bootstrap navbar links lose their padding)
  • the theme's JS does not run (accordions, carousels, dropdowns stay static)
  • the theme's web components stay undefined or get the builder's own version of a shared tag, and rem follows the admin page

The Preview panel has none of these problems: it is an iframe of the real page.

Proposed resolution

  • Render the Canvas in a same-origin iframe, on a new front-theme route, as the Preview does. The iframe runs no builder script and no htmx.
  • The builder page drives it: it listens on the iframe document and sends every request through its own htmx, so the out-of-band swaps of the other islands are unchanged.
  • The Canvas refreshes through a token, like the Preview, reloading into a buffer iframe with the scroll and the selection kept.
  • Drops from the library and the Scaffold reach the iframe through an overlay over it; reordering inside the Canvas uses the iframe's own Sortable.
  • Behind an iframe setting of the Canvas island, off until every Canvas interaction works in it, then on by default.

A spike passed: front theme and its JS in the Canvas, selection, refresh and drops in Chromium and Firefox. An insert refreshes in 400 ms against 696 ms for the shadow DOM Canvas on the same layout.

Remaining tasks

  • Canvas page and iframe mode, with kernel tests.
  • Refresh by token.
  • Selection, contextual menu and keyboard shortcuts across the frame.
  • Drag and drop into and inside the iframe.
  • Highlight and loading state in the iframe, sidebar resize over it.
  • Viewport switcher on the Canvas.
  • Switch the default on, migrate the Canvas Playwright tests.

User interface changes

The Canvas looks and behaves like the real page, theme JS included, and the viewport switcher applies to it. A node cannot be dragged out of the Canvas into the Scaffold or the Navigator at first.

API changes

None.

Data model changes

New iframe setting on the Canvas island of a profile, false by default.

AI-Generated: Yes

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
pdureau’s picture

New iframe setting on the Canvas island of a profile, false by default.

Do we need such a setting? It may be better to use the way which work the best, instead of having 2 different implementations and asking the user to pick one.

a selector spanning a parent and a child component does not match (Bootstrap navbar links lose their padding)

I guess we already have this problem with the dropzone in between a slot and its renderable content. So it may not be introduced to DSD.

the theme's JS does not run (accordions, carousels, dropdowns stay static)
the theme's web components stay undefined or get the builder's own version of a shared tag, and rem follows the admin page

It would be nice to fix that, indeed.

The first issue may be related to is the once() function provided by https://github.com/drupal/drupal/blob/bf4ae811643c6e50e5263e19f8eb28e123... which is always returning an empty array, maybe because the context object passed a third parameter is the full page instead of the shadow dom.

I have no idea about webcomponents being undefined. Maybe it is a similar issue.

mogtofu33’s picture

Do we need such a setting?

Probably no setting, I think the idea was it's because not all themes will have js/css fix necessity.

So it may not be introduced to DSD.

Yes for some part, for example Bootstrap component navbar_nav in a navbar slot, before menu are inline, with the DSD admin menu items are stacked. It's obvious on the Bootstrap recipe that use that.

I have no idea about webcomponents being undefined

I guess it's related to custom wc that needs js init. Not tested as it's very specific and we have no full theme with wc.

My point of view as discussed is that this is a proposition to review and not something that needs to be done, just looking if we have a clean working solution, if not it can be for later.
Will push a draft to review soon.

pdureau’s picture

Assigned: Unassigned » pdureau
Status: Active » Needs review

Hello,

I moved #3562060: Render UI with admin theme to RTBC and I am evaluating this proposal.

I guess the big diff in this MR (+4795 -1086) is because there are rendering modes (DSD & iframe) with a config switch, and if we pick iframe at the end, the MR will be way more compact.

I don't see any in_iframe option in BuilderPanel configuration modal, but that's OK because I only need to test the iframe version here.

pdureau’s picture

Feature review

Work in progress:

UI Suite
DaisyUI
UI Suite
Bootstrap
UI Suite
DSFR
Component rendering & prop updates ✅ ✅ Not tested
Block rendering & settings updates ✅ Not tested
Style utilities updates ✅ ✅ Not tested
Design tokens updates & inheritance ✅ BS5 tokens are a mess No tokens in DSFR
Component library preview popin ✅ ✅ Not tested
Block library preview pop-in ✅ ✅ Not tested
Patterns library preview pop-in ✅ ✅ Not tested
UI Skins theme switch ✅ ✅ Not tested

✅ It works well with Bootstrap Carousel & Accordion.

✅ It is lovely to have Preview floating controls into Canvas panel.

A spike passed: front theme and its JS in the Canvas, selection, refresh and drops in Chromium and Firefox. An insert refreshes in 400 ms against 696 ms for the shadow DOM Canvas on the same layout.

That's great news !!! I don't "feel" this speedup, but the number are impressive, and DSD was already feeling faster/snappier than the current 1.0.x where we render the Builder in front theme.

Code review

This feature woks well and looks "final", and the "price" to pay was a bump of JS code (+20%):

1.0.x 3562060-admin-ui-render 3629497-canvas-iframe
CSS 2 214 2 005 2 073
JS 3 645 3 779 4 254
PHP 16 281 16 468 16 614

So, if my understanding is right:

  • We keep DSD for preview pop-ins in libraries panels
  • We don't use any DSD in Canvas panel anymore

This raises some questions if we go the iframe way:

  • Does it worth to keep 2 such heavy mechanisms? Or can we find a smart trick to get rid of DSD altogether? If not, are there some parts of DSD we are not using anymore and we can remove?
  • Do we need to get back db-block? It was useless in #3562060: Render UI with admin theme because of db-isolate but what about now?
  • We are reintroducing potential bleeding, but it is only from front theme to dropzones and placeholders, so totally manageable. Am I right?
  • Do we still need Preview panel? 😉 just asking. Getting rid of a full Island type is tempting.
pdureau’s picture

Assigned: pdureau » mogtofu33

Hi Jean,

The current draft is very exciting. I have shared my first thoughts in previous comment. What are the next steps?

mogtofu33’s picture

Assigned: mogtofu33 » pdureau

I don't see any in_iframe option in BuilderPanel configuration modal

I forgot to update the summary: the setting is removed.

Do we need to get back db-block

Yes, without the shadow root the reason for #3627001: Invalid HTML nesting in the Canvas takes the contextual menu and the messages out of the builder is back: a wrapper inside markup the browser closes early must be a custom element, or its closing tag closes an ancestor.
Added a commit here to use <db-block> again, for block and component boxes, registered in the iframe.

We are reintroducing potential bleeding

Mostly right, but it went both ways. The front theme reaches the dropzones, placeholders, boxes and the hover label, which is manageable. Ours reached the front theme too: the iframe loaded Shoelace's theme, which sets color-scheme and every --sl-* token on :root, and our token files with generic names. It now loads none of them: the builder page copies the tokens the chrome reads onto the iframe root, so the Canvas chrome also follows the builder's dark theme. The button placeholder is plain markup, as Shoelace's script never ran there.

Do we still need Preview panel?

Yes, it still gives what the Canvas does not: the draft on its pinned page with the theme's regions around it, and the output without dropzones and boxes.

But it's not a first-class feature as before, so the split can be challenged with a preview integrated in the Canvas panel for example.

Does it worth to keep 2 such heavy mechanisms?

Depends on some choices: DSD is still required for the Scaffold rendered components and the library hover previews, but:

  • We could move the library hover previews to an iframe.
  • Not possible with the Scaffold: it puts our admin cards inside a front theme layout, and only shadow DOM slots do that. That real render is opt-in, with an empty allowlist by default. Moving only the previews removes nothing, DSD goes only if both go: about 800 lines of production code, plus the htmx workaround and the :root rewrite.

One part was only used by the shadow DOM Canvas, the lazy build of blocks: SourceLazyBuilder::lazy() now requires a component source.

Next steps: once !468 is merged, I rebase this MR without its commits, so the diff shows only this work.

AI-Generated: Yes (review analysis and part of this text drafted with AI, reviewed and edited by me)

mogtofu33’s picture

Added proposition with full iframe, no more DSD and loss of Scaffold render components.

pdureau’s picture

OK, cool, so now we have 2 MR:

1.0.x MR 469: 3629497-canvas-iframe MR 470: 3629497-iframe-only
Canvas DSD iframe iframe
Scaffold DSD DSD iframe
Preview iframe iframe iframe
Library panels preview DSD DSD iframe
JS: files & LOC 28 / 3779 31 / 4288: canvas_frame, canvas_frame_inner & canvas_query added 29 / 4187: shadow_root_styles.js & htmx_shadow_dom removed
PHP (src/ only): files & LOC 128 / 11027 129 / 11168: CanvasController added 126 / 10881: DeclarativeShadowDomRenderer, SourceLazyBuilder & SubRequestInternalController removed

The removal of the hook theme and the 2 templates (html--ds-shadow-dom.html.twig page--ds-shadow-dom.html.twig) is warmly welcomed.

Currently testing the 2 branches. If they provide the same features with the same perf, I would advocate to go full iframe.

I am taking time because there is something "to good to be true" here:

  • iframe is a old, legacy, technology. How come we didn't get the idea before? Maybe because the success of DSD has been the incentive
  • iframe is supposed to be a slow and clunky technology, and DSD the modern/light one. How come we have better perf? Maybe because the server side logic is simpler (no sub-requests)
  • iframe was also supposed to be hard to resize according to content...

Let's check

mogtofu33’s picture

Note that #3630345: Preview as a switch on the Canvas, and in a new tab, instead of a split view is progressing in top of 3629497-iframe-only.
To provide a better experience with preview, it includes some minor fixes on current iframe branch and helped discover performance issues fixed on display builder, and some other related issue for performance problems in UI Patterns:

pdureau’s picture

Note that #3630345: Preview as a switch on the Canvas, and in a new tab, instead of a split view, and in a new tab, instead of a split view is progressing in top of 3629497-iframe-only.

OK, thanks, having a look on both.

pdureau’s picture

Assigned: pdureau » Unassigned
Status: Needs review » Closed (outdated)

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.