Vaadin Web Components and View Transitions

Hello everyone, has anyone had any satisfactory experience using Vaadin Web Components on animated pages with the View Transitions API?
My experience has been with problems, view transition in Astro replace the current page with the contents of the target URL causing Vaadin style nodes to no longer be included in DOM loaded from the target URL, resulting in the loss of those styles in the components.

Hi, I’ve had the same experience with Astro.

May be related: client:only ui component loses its style in a persistent island · Issue #8114 · withastro/astro · GitHub

While looking for a proper fix, I’m currently using this nasty workaround to mitigate the issue:

const restoredNodes = new Set<Element>();

function recordRestoredNodes() {
  document.head
    .querySelectorAll('style[id^="lumo-"]')
    .forEach((node) => restoredNodes.add(node));
}

recordRestoredNodes();

const mutationObserver = new MutationObserver(() => {
  recordRestoredNodes();
  restoredNodes.forEach((node) => {
    if (!document.head.contains(node)) {
      document.head.appendChild(node);
    }
  });
});

mutationObserver.observe(document.head, { childList: true });


1 Like

Thank you for the answer. I will try to use your workaround, in my case I am using the Vaadin components within an HTML markup of .astro components, I also think that there are Vaadin style nodes that do not have the id=“lumo*”, I may have to make some changes, I’ll let you know how it goes.

Update: Astro 4.15 has introduced the possibility to build a custom swap function for the view transitions. Leaving out the part that replaces <head> element solves the issue with the dynamically added style nodes getting removed on navigate.

Example:

import { swapFunctions } from 'astro:transitions/client';

function swap(doc: Document) {
  swapFunctions.deselectScripts(doc);
  swapFunctions.swapRootAttributes(doc);

  // Exclude swapHeadElements to keep the original <head> element
  // swapFunctions.swapHeadElements(doc);

  const restoreFocusFunction = swapFunctions.saveFocus();
  swapFunctions.swapBodyElement(doc.body, document.body);
  restoreFocusFunction();
}

document.addEventListener('astro:before-swap', (event) => {
  event.swap = () => swap(event.newDocument);
});