See the original issue :#8543.
The current behavior is by design but I don't even know how to style the embedded component since it's inside shadow root of the generated wrapper.
I've made already a ticket in the docs about styling of embedded components.
May be we should provide API for WebComponentExporter which allows to include styles which works for its content and allow to style the embedded component in its shadow root.
The only way to do styling which I see at the moment is: make the embedded component as a web component ( e.g. a Polymer element) and "inline styling" there so that it's local and doesn't leak globally.
But it's silly because if I want to use only standard HTML components (like div) I have to make my own wrapper just to style it.
It's reasonable to add styling to already existing wrapper which we generate.
We haven鈥檛 actually tested this yet, but we will most likely need better support for this. Our upcoming documentation system uses Flow embedding for Java component examples, and if customers have done theme customizations using global style sheets, then those would not work for the component examples.
I stumbled over this ticket because I need to embed a vaadin 14 component in a plain HTML page.
All works fine, except the styling is completely lost.
Is there a way to include css in the shadow dom of the exported web component?
Or is it really necessary to use the getElement().getStyle().set(..., ...) for each and every style I need??
While the solution to this issue would most likely be adding a new feature/capabilities, the fact that this is not possible (easily) is basically a bug since we didn't consider this properly and have not clearly communicated that this is a known limitation.
I found a workaround for now.
Simply extend the following class when writing an embedded web-component:
Then you need to place the CSS file in the JAR file (for maven this would be under src/main/resources directory).
In the web-component you can then call addStyle() and pass the location of the CSS relative to you component class in the JAR file (or start the path with / and make it absolute to the root of the JAR).
public abstract class StyledWebComponentBase extends Div {
public void addStyle(final String path) {
final Element style = new Element("style");
style.setText(getCss(path));
getElement().appendChild(style);
}
private String getCss(final String path) {
try (final InputStream resourceAsStream = getClass().getResourceAsStream(path)) {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final byte[] buffer = new byte[1024];
int len;
while ((len = resourceAsStream.read(buffer)) > 0) {
((OutputStream) outputStream).write(buffer, 0, len);
}
outputStream.flush();
return new String(outputStream.toByteArray(), UTF_8);
} catch (IOException ignored) {
// ignore and set the background to bright red to make it visible that styling failed
return ":host {background-color: red;}";
}
}
Hi, is there any news for this? In which Vaadin version can the enhancement be expected?
Actually yes, although with a slightly different solution. We're working on a new theming mechanism (https://github.com/vaadin/platform/issues/1571) that will solve this, amongst other things, which will come to V19 if all goes well.
Specifically this part in the AC:
The theme's global css can be applied to the shadow dom of custom web components such as application views built with TS+Lit, and java components exported using the WebComponentExporter feature.
In short:
What are the "global" styles in case of the WebComponentExporter?
Can they be defined in the WebComponentExporter class as a @Style annotation?
Also if I export multiple web components in a single embedded application.
Can I have different styles for the different web components or will they all contain the same style entry?
Well, assuming you have a Flow component, like
public class FooBar extends MenuBar { ... }
the way you'd apply styling to it is by giving it a css classname
setClassName("foobar");
then you create a stylesheet foobar.css and write the css for the component there
.foobar { color:red; }
That's good old fasioned global css, as it's not scoped inside a shadow root.
And the problem with the exported web component is that now there's suddenly a shadow root around the component, so there's no way for the styles in foobar.css to be applied to the component.
So what the new theming system does is to automatically inject foobar.css inside of that shadow root, so that it's actually applied to the component, just as they would be in a Flow app, as long as foobar.css is in a theme folder (e.g. frontend/theme/foo) that's applied to the project using @Theme("foo");
So, if you have a second component, FooField, that uses the foofield.css stylesheet, both stylesheets will be injected into the shadow root of both components. But of course they use different selectors for their styles, so that shouldn't be a problem, just as if they were used in a regular Flow app without exporting as web components.
As with the new theming mechanism, the "application theme" will be automatically applied for the exported web components when the @Theme annotation is used for the MyComponent extends WebComponentExporter. This should be enough for the doc-builder case too as there it would be read from the abstract class https://github.com/vaadin/docs/blob/361202c61cac1c20ae24ac8e9fbe65cb971cdd64/src/main/java/com/vaadin/demo/DemoExporter.java#L8 and if necessary can be overridden from in the component specific exporter https://github.com/vaadin/docs/blob/master/src/main/java/com/vaadin/demo/component/accordion/AccordionBasic.java.
The theme should be applied similarly as done in the PoC https://github.com/vaadin/flow/blob/poc/applicationTheme/flow-server/src/main/resources/plugins/application-theme-plugin/theme-generator.js#L134 (without the parent theme feature at this point).
Most helpful comment
Well, assuming you have a Flow component, like
public class FooBar extends MenuBar { ... }the way you'd apply styling to it is by giving it a css classname
setClassName("foobar");then you create a stylesheet foobar.css and write the css for the component there
.foobar { color:red; }That's good old fasioned global css, as it's not scoped inside a shadow root.
And the problem with the exported web component is that now there's suddenly a shadow root around the component, so there's no way for the styles in foobar.css to be applied to the component.
So what the new theming system does is to automatically inject foobar.css inside of that shadow root, so that it's actually applied to the component, just as they would be in a Flow app, as long as
foobar.cssis in a theme folder (e.g.frontend/theme/foo) that's applied to the project using@Theme("foo");So, if you have a second component,
FooField, that uses thefoofield.cssstylesheet, both stylesheets will be injected into the shadow root of both components. But of course they use different selectors for their styles, so that shouldn't be a problem, just as if they were used in a regular Flow app without exporting as web components.