Consider adding "in_preview" var to components

Created on 7 December 2024, 15 days ago

Overview

Some interactive components, such as accordions, have default states that prevent successful usage within Experience Builder.

For example, if an accordion component is collapsed by default, meaning that it's slot is effectively inaccessible on render, then the drag/drop UX doesn't work to add things to it.

Proposed resolution

Layout builder and block content templates have an "in_preview" variable that can be used to customize how rendering happens depending on whether the layout or block is being edited, or if it is being rendered otherwise.

We use this feature in our accordion componentry and also to display placeholder information on the layout builder UI for blocks that may be conditionally visible based on external conditions, like time of day.

Would it be feasible to add an equivalent variable to SDC components so that they can react in the same fashion? Or perhaps another mechanism already that needs some docs written?

User interface changes

None (until extension authors capitalize on the new feature, then 🥳🥳🥳)

Feature request
Status

Active

Version

0.0

Component

Page builder

Created by

🇺🇸United States luke.leber Pennsylvania

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @luke.leber
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    AFAICT this is in direct conflict with @lauriii's product requirement 3. Real-time page preview:

    […] Custom component code should not have to be aware that it may be rendered in the page builder.

  • 🇺🇸United States luke.leber Pennsylvania

    Attached screenshot with more context.

  • 🇺🇸United States luke.leber Pennsylvania
  • 🇺🇸United States luke.leber Pennsylvania

    I suppose that an alternative approach might be to allow certain rendered elements receive input events, but that seems like it'd be quite the technical lift to accomplish.

  • 🇺🇸United States effulgentsia

    allow certain rendered elements receive input events

    That should already work with Initial support for allowing interaction with the preview Active . Not sure if state is retained when exiting preview though, or if the whole canvas gets re-rendered and therefore the accordion reverts to collapsed.

    Even when the accordion is collapsed, are you able to move a component into a hidden slot via the Layers panel (left sidebar)? That's certainly not enough of a solution, but I'm curious if that at least works in the meantime.

  • 🇺🇸United States luke.leber Pennsylvania

    Even when the accordion is collapsed, are you able to move a component into a hidden slot via the Layers panel (left sidebar)?

    Yep. That works.

    That should already work with #3486785: Initial support for allowing interaction with the preview. Not sure if state is retained when exiting preview though, or if the whole canvas gets re-rendered and therefore the accordion reverts to collapsed.

    Yep, the preview mode works perfectly -- things are able to be interacted with just fine in there. It's just the non-preview mode where it's impossible to use the mouse and/or keyboard to expand/collapse interactive things.

    While this can be worked around for accordions (through adding an "expand by default" prop and temporarily adjust that while adding content), I don't think it'll be quite as easy for other interactive UI patterns, like multiple tabs. For completeness, this is how we've set up our Tabs implementation in Layout Builder (dragging a block over a tab activator will actually activate the tab in the LB editor):

  • 🇺🇸United States effulgentsia

    It's just the non-preview mode where it's impossible to use the mouse and/or keyboard to expand/collapse interactive things.

    But why do you need to? What's wrong with whenever you want to interact with the component to go into preview mode, interact, then exit preview mode? Is the problem that when you exit preview mode the canvas is re-rendered in a way that resets any interaction that you did while in preview mode? If so, I think that's an issue that we should open and fix.

  • 🇺🇸United States luke.leber Pennsylvania

    Here's a gif of the behavior (described in previous comment).

  • 🇬🇧United Kingdom jessebaker

    I actually snuck into 0.x a very work-in-progress/hacky (and totally untested by anyone except me) feature where you can press and hold the 'V' key and it will hide the overlay UI and allow you to interact with the page inside the iFrame. *

    I use it for debugging and I have some vague intentions to build it out into a full feature in the fullness of time, but I'm curious if it is enough to work around your problem (and as such would be a good use case for us to consider more fully fleshing out that feature).

    As for your request, when I was building Visual Page Builder for Site Studio we had to add in a variable/property to let Site Studio interactive components know they were being rendered in the VPB for very similar reasons to the ones you are facing. I think one of the main reasons was a gallery slider that would auto-transition to the next slide every few seconds which was very undesirable when trying edit the slides!

    * if you get stuck in the Visual mode, make sure you focus outside the iFrame and press 'v' again a few times and it will unstick you. The issue is the keyup event when you let go of V sometimes gets swallowed by the iFrame. Like I said, very work-in-progress!

  • 🇺🇸United States luke.leber Pennsylvania

    That's pretty neat, @jessebaker. It definitely *helps*, but the editing UX still seems off as the accordion seems to re-flip back to closed every time it's re-rendered.

    Strangely enough, the newly added component seems to be selected by default even after re-paint and it's hidden.

  • 🇬🇧United Kingdom jessebaker

    Hmm, that's a really difficult challenge.

    There are actually 2 iframe elements one on top of the other. Each time any data changes, the hidden iframe is updated with the new preview and once it has loaded, the iframes are swapped so you can see the changes.

    Because the page is re-rendered server side whenever there are any changes, the iframe swapping has to be done to hide the document loading and stop any FOUC issues/flickering.

    As a result of that implementation though, no front end state on the page is maintained between data updates.

    Off the top of my head I don't have an immediate thought of how to even begin addressing that.

  • 🇺🇸United States luke.leber Pennsylvania

    It's actually pretty simple to resolve if the component knows if it's being observed in Experience Builder.

    A custom twig extension...

    class XBExtension extends AbstractExtension  {
      public function getFunctions() {
        return parent::getFunctions() + [
          new TwigFunction('is_xb_editing', [
            $this,
            'isXbEditing',
          ]),
        ];
      }
    
      public function isXbEditing() {
        return \Drupal::routeMatch()->getRouteName() === 'experience_builder.api.preview';
      }
    }
    

    ...and using it in the SDC template:

    {% set expanded = is_xb_editing() %} {# <-- "in_preview" variable-like-thing #}
    
    {% include '@my-upstream-components/accordion.twig' %}
    

    That said, I wouldn't recommend writing this off as a niche problem. I can't think of any interactive / progressive disclosure elements from *any* design systems that wouldn't need a mechanism like this. I think it's more along the lines of not having any example components available in XB to have stepped on this yet. It'd be really unfortunate for each design system to have to roll their own "in_preview"-like feature.

  • 🇺🇸United States luke.leber Pennsylvania

    Added copy/paste example to I.S. w/o any external dependencies :-).

  • 🇺🇸United States luke.leber Pennsylvania
  • 🇫🇮Finland lauriii Finland

    I agree with the premise from #2 that the proposal to add in_preview variable is in conflict with the idea that the components shouldn't have to be aware that they are being rendered in XB. That said, think we will eventually have to add in_preview as a tool to help working around the limitations of the editor in the complex use cases.

    There's an alternative approach to this, which is to add a new property that allows toggling the accordion. This would essentially allow setting the default value for the open/closed state, but would also allow opening the accordion item in XB.

  • 🇬🇧United Kingdom jessebaker

    I'm not sure your alternative approach in #16 @lauriii would be enough to handle the scenario of disabling an auto-playing image slider for instance.

    Maybe it's just semantics but "Custom component code should not have to be aware..." - suggests that components must work without being aware they are in the editor but doesn't say that they can't be told they are in the editor if that allows for someone to improve the DX when building them out.

    I think we have work arounds planned to mean that any/all components will work and be useable (e.g. falling back to using the layers panel) which fulfils that requirement but we shouldn't intentionally hamper more advanced use cases just to meet that requirement.

  • 🇫🇮Finland lauriii Finland

    To clarify my comment from #16, I'm +1 to adding the in_preview (or similar variable). At the same time, I think that we should continue improving our tools to better facilitate an seamless integration of components for common use cases, even if they come with some interaction.

Production build 0.71.5 2024