visit
To make it easy to handle when and where to put the shadow content, QCObjects has Shadowed Components.
// in your components package
Class('ShadowedCardComponent',Component,{
name:'card',
/* If shadowed is true, the DOM will be shadowed, default is false */
shadowed:true,
cached:false,
data:{}
})
In the above definition, you can use the hidden static property shadowed to let QCObjects to know it has to shadow the DOM of the component body.
Then, you are able to use this definition into your html component tag, like this:<!-- in your html layout file -->
<component componentClass="ShadowedCardComponent" ></component>
<component name="card" shadowed="true"></component>
Both, lighting components and shadowed components are accesible from the global components stack, the main difference is that in the instance of every shadowed component will be a new hidden property (readonly) called shadowedRoot, that is replacing the behaviour of the body, now, if you have any elements to add to the component content, you need to use componentInstance.shadowRoot.appendChild(element) instead of componentInstance.body.append(element)
In simple and easy words, Composition is when you dynamically place elements of an object instance into blocks defined on its inherited instance. The resulting composed object instance will be mutating its behaviour as a result of the dynamic blocks mixing.
The shadow DOM is a hidden tree, that is allocated in a private scope, and it is populating its content to the light DOM, that is visible and accesible from the global scope. You can place light DOM elements over the shadow DOM elements, mutating the behaviour of the final flattened tree. This is called shadow DOM composition.<component name="card" >
<!-- this content is generated by templates/components/card.tpl.html file -->
<div class="card">
<img src="img/avatar.png" alt="Avatar" style="width:100%">
<div class="container">
<h4><b>Card Title</b></h4>
<p>Card Description</p>
</div>
</div>
</component>
<component name="card" shadowed="true">
<!-- this content is generated by templates/components/card.tpl.html file -->
<div class="shadowHost">
#shadow-root
<div class="card">
<img src="img/avatar.png" alt="Avatar" style="width:100%">
<div class="container">
<h4><b>Card Title</b></h4>
<p>Card Description</p>
</div>
</div>
</div>
</component>
In this case, a light <div> component was added dynamically to enclose the shadow DOM, this is always done by QCObjects in order to asure there will be no restrictions by the HTML spec over the different browsers that support shadow DOM.
<!-- file: templates/components/card.tpl.html -->
<div class="card">
<img src="img/avatar.png" alt="Avatar" style="width:100%">
<div class="container">
<h4><slot name="card_title"></slot></h4>
<slot name="card_description"></slot>
</div>
</div>
<!-- file: main-layout.html or wherever you want to place your component -->
<component name="card" shadowed="true">
<b slot="card_title">Card Title</b>
<p slot="card_description">Card Description</p>
</component>
In a shadowed component, you can override the content of the slot elements using custom blocks.
And the resulting flattened DOM tree will be like this:<!-- file: main-layout.html or wherever you want to place your component -->
<component name="card" shadowed="true">
<!-- this content is generated by templates/components/card.tpl.html file -->
<div class="shadowHost">
#shadow-root
<div class="card">
<img src="img/avatar.png" alt="Avatar" style="width:100%">
<div class="container">
<h4>
<b slot="card_title">Card Title</b>
</h4>
<p slot="card_description">Card Description</p>
</div>
</div>
</div>
</component>
<!-- file: main-layout.html or wherever you want to place your component -->
<component name="card" shadowed="true">
<b slot="card_title">{{title}}</b>
<p slot="card_description">{{description}}</p>
</component>
For shadowed components, it is recommended to place your style rules into the dynamic template file, commonly named with the extension tpl.html, so the styles will be enabled only for the scope of the shadowed component. You can reference the main element of the shadowed DOM by using :hostelement in your style declaration, like this:
<!-- file: templates/components/card.tpl.html -->
<style>
:host {
display: block;
}
/* Also you can import styles from another css file */
@import url("./css/components/card.css");
</style>
<div class="card">
<img src="img/avatar.png" alt="Avatar" style="width:100%">
<div class="container">
<h4><slot name="card_title"></slot></h4>
<slot name="card_description"></slot>
</div>
</div>