-
Notifications
You must be signed in to change notification settings - Fork 319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
litElement doesn't support nested components #824
Comments
Yep this is definitely supported. With web components you need a name attribute on your slot element, and then you need to add a slot attribute to your nested components that matches the slot's name |
@jordanaustin Tried that. And the result is the same. <parent-element>
<nested-element slot="inner"></nested-element>
<nested-element slot="inner"></nested-element>
</parent-element> class ParentElement extends LitElement {
constructor() {
super();
}
render() {
return html`<div class="parent"><slot name="inner"></slot></div>`;
}
}
customElements.define('parent-element', ParentElement);
class NestedElement extends LitElement {
constructor() {
super();
}
render() {
return html`<div class="nested"></div>`;
}
}
customElements.define('nested-element', NestedElement); <parent-element>
<!---->
<div class="parent"><slot name="inner"></slot></div>
<!---->
<nested-element slot="inner">
<!---->
<div class="nested"></div>
<!---->
</nested-element>
<nested-element slot="inner">
<!---->
<div class="nested"></div>
<!---->
</nested-element>
</parent-element> Using |
You're initial samples seem to be working fine in my test: https://stackblitz.com/edit/as9syq?file=my-element.js |
@abraham Ah bugger so I forgot to add to my question I use: createRenderRoot() {
return this;
} This is because I want all components to inherit the CSS from the main stylesheet of the page and NOT have encapsulation. But it seems this then causes the problem I have posted above... So how can I allow the nesting of components but allow the components to use the styles from the top-level page they are used on? |
You can't not use shadow DOM and use I'd really recommend not using |
@justinfagnani How can I nest Web Components but allow them to inherit the styling from the page that they are on? Without the |
I can't imagine how Light DOM rendering would be conceived as a misfeature for anyone who seeks to build entire apps or sites with a pure LitElement approach and not least for the reason @iamdriz states. I would prefer to offer a |
Is this actually a limitation of LitElement or is it Web Components themselves that are where this limitation lies? If it's purely the way in which LitElement currently works then it'd be great to see someway of solving this... if not... I'm not sure what we can do... seems a shame if the ability to have a Light DOM and nest components is impossible though. |
This has nothing to do with web components or lit-element, it's simply how HTML and the DOM work. In most js frameworks, the framework has control over the entire tree so it can render things in different places as it sees fit. Web components are actual dom nodes, so anything they render goes into that dom node. Rendering web components is async, so it cannot assume anything about it's parent or child nodes. In the browser the slotting issue is solved with shadow dom. You can nest web components just fine: <element-a>
<element-b></element-b>
</element-a> This will render element-a, with element-b inside. However, if this.innerHTML = '' it will remove The default behavior of You could do something like this: class ElementA extends LitElement {
createRenderRoot() {
const contentWrapper = document.createElement('div');
this.appendChild(contentWrapper);
return contentWrapper;
}
} this way element-a will render into a wrapper div, and won't overwrite the other child nodes. If you want to wrap the content of element-a around the "slotted" content given by the parent, it gets pretty complex. Web components render async, so the child nodes could come in at any later time, and the parent could make changes which need to be tracked. Moving around live nodes like that isn't a good idea. However, if both elements use lit-html, you could set the content to render as a property: class ElementA extends LitElement {
static get properties() {
return {
slotTemplate: { type: Object }
};
}
createRenderRoot() {
return this;
}
render() {
return html`
<div>${this.slotTemplate}</div>
`;
}
} <element-a .slotTemplate=${html`<element-b></element-b>`}></element-a> This is essentially how most frameworks work as well, just with a more declarative syntax. |
There has been a similar discussion in #553 and it was closed. See #553 (comment). So this is likely a duplicate and should be closed as well. |
the root of this issue, and #533, is that developers are frustrated by the shadow-dom's lack of options for application-level themeing our current options for application-level themeing:
future solutions for application-level themeing:
|
For those who want to "pierce" or "inject" a broader theme stylesheet into all instances of a LitElement, there's another option that hasn't been mentioned so far: LitElement's static So, instead of this: customElements.define('x-my-element', class extends LitElement {
static get styles() {
return css`.whatever{}`
}
}) You can export something like this: export default theme => {
customElements.define('x-my-element', class extends LitElement {
static get styles() {
return [theme, css`.whatever{}`]
}
}
} Then you can use your globally-themed component like: import MyElement from './my-element.js'
const theme = css`.global-things{}`
MyElement(theme) |
You can also use themes in an inheritance pattern. class BaseElement extends LitElement {
static get styles() {
return css`...`;
}
}
class SpecificElement extends BaseElement {
static get styles() {
return [
super.styles,
css`...`,
];
}
} |
I wonder if combining the two strategies above you could arrive at a generic 'Styled component' that would inject a theme into whatever LitElement you provide, eg: styled.js: export default (Base, theme) => {
return class extends Base {
static get styles() {
return [theme, super.styles]
}
}
} import Component from './component.js'
import Styled from './styled.js'
import theme from './theme.js'
customElements.define('my-component', Styled(Component, theme)) |
I have solved the inherit problem + shadowRoot with a base class like this: Base Class (Lit-Element)
My component who use my custom base component:
We just need export the base component as we want, import him and call super methods. Lit-element are very smart, the import of material icons (request) will occur just one time if you take a look in console network, so, this is very cool! Thank you Lit devs! |
So... this issue is mostly about how standard shadow DOM works. Shadow roots don't inherit page styles, and it's required if you want to use Until then the approach of importing styles is good, and we're working on a theming system that you can track here: https://github.com/Polymer/lit-element/issues/835 I'm going to close this in favor of the more specific and actionable topic in #825 and for the standards side I just opened WICG/webcomponents#864 . It'd be great to get some actual web component users in there with their real-world use cases. |
It doesn't seem litElement allows you to nest elements in the HTML page itself.
For example If I wanted to do this:
And I declared these elements like so:
It ignores the nesting and prints them like:
So whilst it keeps the nested components it's not honouring that the HTML itself should be nested inside each other.
In fact, if I remove the
<slot></slot>
it still prints it exactly the same... so it seems litElement doesn't care about the nesting of the components...Does litElement support nested components? Or is this an error in the code?
The text was updated successfully, but these errors were encountered: