vaadin / web-components

A set of high-quality standards based web components for enterprise web applications. Part of Vaadin 20+
https://vaadin.com/docs/latest/components
430 stars 82 forks source link

Support renaming elements and using multiple tags on the same page without conflicts #7055

Open Artur- opened 6 months ago

Artur- commented 6 months ago

Describe your motivation

In copilot we would like to use the Vaadin components but cannot directly import e.g. button for a couple of reasons:

  1. We do not know if we should import the bare version, the Lumo version or the Material version. If we import the wrong version and the application later imports another version, the theme from the application version will not be applied and a warning printed to the browser console that the element was finalized before a style module was registered.
  2. Application theme rules, both injected into the component shadow root and ::part style rules are applied also to components used for copilot. The themes should be independent.

Describe the solution you'd like

We would like to use e.g. text field and call it copilot-text-field. This would avoid most problems but currently cannot be done because

  1. There is no side effect free import that does not register vaadin-text-field so we will always hit problem 1 above
  2. Even if we had a side effect free import, text field internally registers and uses sub elements like vaadin-input-container which must also be renamed to e.g. copilot-input-container so these internal elements will have application theming applied to them

Describe alternatives you've considered

We could fork the whole component set and do find and replace but this is sounds like the wrong way to go for many reasons

Additional context

No response

web-padawan commented 6 months ago

Depends on #6999 (which also suggests introducing side effects free imports, but for other use case).

Legioth commented 6 months ago

As discussed in Slack, we could consider a wrapped html function for rendering children with custom tag names. The wrapper would replace strings from the raw template expression before passing it to the original.

const html = htmlReplace(originalHtml, {'vaadin-button': 'copilot-button'});
return html`<vaadin-button>Click me</vaadin-button>`;
web-padawan commented 6 months ago

Actually, in case of Polymer we can create a custom html tag function that returns <template> element. Example:

import { PolymerElement } from '@polymer/polymer';

const htmlReplace = function htmlReplace(replacements) {
  // Create a custom html literal function
  return function (strings, ...values) {
    const replaced = strings.map((string) => {
      Object.entries(replacements).forEach(([from, to]) => {
        string = string.replaceAll(from, to);
      });
      return string;
    });

    // Return HTMLTemplateElement to be cloned
    const template = document.createElement('template');
    template.innerHTML = replaced.join('');
    return template;
  };
};

class MyElement extends PolymerElement {
  static get template() {
    const html = htmlReplace({ 'vaadin-button': 'copilot-button' });
    return html`<vaadin-button>Button</vaadin-button>`;
  }

  static get properties() {
    return {
      disabled: {
        type: Boolean,
      },
    };
  }
}

customElements.define('my-test', MyElement);

For Lit based versions, we would need to use unsafeStatic directive to make tag names customizable.

web-padawan commented 6 months ago

One more thing to address in scope of this issue would be to replace usage of registerStyles in src folders e.g.

https://github.com/vaadin/web-components/blob/08563b9e009eb7f90921c172ab7982d64651aea2/packages/context-menu/src/vaadin-context-menu-overlay.js#L15-L17

These currently have hardcoded HTML tag names. Instead, we should be able to move them into static get template() by using the custom html function (e.g. the one suggested above) that wouldn't prevent interpolating like Polymer does.

robrez commented 4 months ago

I've had some similar interest for some time.

Within my organization, we've vended some components that utilize vaadin (unthemed) as building blocks for my-org-themed components. This looks similar to what was outlined by original commenter: vaadin-button => myorg-button... not dissimilar from the premise of "lion" or "microsoft fast (foundation)"; I've been using vaadin + custom theming long before either of those packages existed and have a lot of respect for you all, so using vaadin for a functional base was my choice.

Here are some lessons I learned along the way.

Kind regards