163 lines
4.4 KiB
Plaintext
163 lines
4.4 KiB
Plaintext
|
# ShadowTemplate
|
||
|
|
||
|
A component to aid creating ShadowDOM based components (when required), heavily
|
||
|
inspired by the upcoming Declarative Shadow DOM spec, a new way to implement and
|
||
|
use Shadow DOM directly in HTML.
|
||
|
|
||
|
Instead of passing `shadowroot="open|closed"` as you would with Declarative
|
||
|
Shadow DOM we have a `@shadowRoot` argument to which you would pass the actual
|
||
|
Shadow DOM element (which itself either open or closed). You can get a reference
|
||
|
to this by using the `{{attach-shadow}}` modifier.
|
||
|
|
||
|
Additionally a `@stylesheets` argument is made available for you to optionally
|
||
|
pass completely isolated, scoped, constructable stylesheets to be used for the
|
||
|
Shadow DOM tree (you can also continue to use `<style>` within the template
|
||
|
itself also if necessary).
|
||
|
|
||
|
For the moment we'd generally use a standard div element and add Shadow DOM to
|
||
|
it, but as shown in the second example, you could also use it to make
|
||
|
Glimmerized native custom-elements using Declarative ShadowDOM and
|
||
|
Constructable Stylesheets.
|
||
|
|
||
|
**Important:** As ShadowDOM elements are completely isolated please take care
|
||
|
to use the features available (slots/parts etc) to make sure components built in
|
||
|
this way can make use of a11y functionality, i.e. any elements having necessary
|
||
|
`id` relationships for a11y reasons should be slotted to ensure that the all
|
||
|
`id`s remain in the LightDOM. Native form controls such as inputs etc should
|
||
|
also be slotted in order to keep them in the LightDOM to ensure that native
|
||
|
form functionality continues to work.
|
||
|
|
||
|
Beside several advantages of isolated DOM/CSS ShadowDOM slots can also be used
|
||
|
within conditionals, something which is currently not possible with
|
||
|
Glimmer/Ember slots. Mixing Glimmer/Handlebars conditionals with native
|
||
|
ShadowDOM slots will give you this additional feature (see truthy conditional in
|
||
|
the example below).
|
||
|
|
||
|
```hbs preview-template
|
||
|
<div
|
||
|
class={{class-map
|
||
|
"component-name"
|
||
|
}}
|
||
|
...attributes
|
||
|
{{attach-shadow (set this 'shadow')}}
|
||
|
>
|
||
|
<ShadowTemplate
|
||
|
@shadowRoot={{this.shadow}}
|
||
|
@stylesheets={{css '
|
||
|
:host {
|
||
|
background-color: rgb(var(--tone-strawberry-500) / 20%);
|
||
|
padding: 1rem; /* 16px */
|
||
|
}
|
||
|
header {
|
||
|
color: purple;
|
||
|
}
|
||
|
p {
|
||
|
color: green;
|
||
|
}
|
||
|
|
||
|
::slotted(header) {
|
||
|
color: blue;
|
||
|
}
|
||
|
::slotted(p) {
|
||
|
color: red;
|
||
|
}
|
||
|
header {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
}
|
||
|
header::before {
|
||
|
margin-right: 0.375rem; /* 6px */
|
||
|
}
|
||
|
'}}
|
||
|
>
|
||
|
<header part="header">
|
||
|
<slot name="header">
|
||
|
<h1>Default Header</h1>
|
||
|
</slot>
|
||
|
</header>
|
||
|
<!-- Wrap the slot in a conditional -->
|
||
|
{{#if true}}
|
||
|
<slot name="body">
|
||
|
<p>Default Body</p>
|
||
|
</slot>
|
||
|
{{/if}}
|
||
|
<slot>
|
||
|
<!-- The default slot -->
|
||
|
</slot>
|
||
|
</ShadowTemplate>
|
||
|
</div>
|
||
|
```
|
||
|
|
||
|
```css
|
||
|
.component-name::part(header)::before {
|
||
|
@extend %with-logo-consul-color-icon, %as-pseudo;
|
||
|
width: 2rem; /* 32px */
|
||
|
height: 2rem; /* 32px */
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Example with a custom element. **Please note:** These must still be instantiated
|
||
|
using Glimmer syntax i.e. `<ComponentName />` not `<component-name />` but a
|
||
|
`<component-name />` element will be rendered to the DOM instead of a `<div>`.
|
||
|
|
||
|
```hbs preview-template
|
||
|
<component-name
|
||
|
...attributes
|
||
|
{{attach-shadow (set this 'shadow')}}
|
||
|
>
|
||
|
<ShadowTemplate
|
||
|
@shadowRoot={{this.shadow}}
|
||
|
@stylesheets={{css '
|
||
|
header {
|
||
|
color: purple;
|
||
|
}
|
||
|
p {
|
||
|
color: green;
|
||
|
}
|
||
|
|
||
|
::slotted(header) {
|
||
|
color: blue;
|
||
|
}
|
||
|
::slotted(p) {
|
||
|
color: red;
|
||
|
}
|
||
|
header {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
}
|
||
|
header::before {
|
||
|
margin-right: 0.375rem; /* 6px */
|
||
|
}
|
||
|
'}}
|
||
|
>
|
||
|
<header part="header">
|
||
|
<slot name="header">
|
||
|
<h1>Default Header</h1>
|
||
|
</slot>
|
||
|
</header>
|
||
|
{{#if true}}
|
||
|
<slot name="body">
|
||
|
<p>Default Body</p>
|
||
|
</slot>
|
||
|
{{/if}}
|
||
|
<slot>
|
||
|
<!-- The default slot -->
|
||
|
</slot>
|
||
|
</ShadowTemplate>
|
||
|
</component-name>
|
||
|
```
|
||
|
|
||
|
```css
|
||
|
component-name::part(header)::before {
|
||
|
@extend %with-logo-consul-color-icon, %as-pseudo;
|
||
|
width: 2rem; /* 32px */
|
||
|
height: 2rem; /* 32px */
|
||
|
}
|
||
|
```
|
||
|
## Arguments
|
||
|
|
||
|
| Argument | Type | Default | Description |
|
||
|
| --- | --- | --- | --- |
|
||
|
| `shadowRoot` | `ShadowRoot` | | A reference to a shadow root (probably retrived using the `{{attach-shadow}}` modifier |
|
||
|
| `stylesheets` | `CSSResultGroup` | | Stylesheets to be adopted by the ShadowRoot |
|