*shadow
Summary
*shadow defines a visible shadow template that can be connected to a host element with *host.
The directive is written on a <template> element. It defines the Shadow DOM side of the structure. A host element can then refer to that template by name.
Sercrod does not reimplement slot behavior. Standard <slot> and slot="..." assignment is handled by the browser.
Key points:
*shadowdefines a named shadow template.- It is written on
<template>, not on the host element. *hostconnects a host element to a named*shadowtemplate.- The shadow template usually contains structure,
<style>, and standard<slot>elements. - Sercrod connects the template and the host. Slot assignment remains standard browser behavior.
- Light DOM children are not physically moved into the Shadow DOM.
Basic example
A simple shadow template and a host element that uses it:
<template *shadow="'messagebox'">
<section class="message-box">
<div class="message-box-title">
<slot name="title"></slot>
</div>
<div class="message-box-message">
<slot name="message"></slot>
</div>
</section>
</template>
<message-box *host="'messagebox'">
<p slot="message">Maintenance will be performed on May 20.</p>
<h2 slot="title">Notice</h2>
</message-box>
Behavior:
<template *shadow="'messagebox'">defines a shadow template namedmessagebox.<message-box *host="'messagebox'">connects the host element to that shadow template.slot="title"is displayed at<slot name="title">.slot="message"is displayed at<slot name="message">.- The host writes the message first and the title second, but the shadow template decides the display positions.
Recommended syntax
The recommended form is to use an explicit connection name as a string literal.
The value of *shadow and *host is evaluated as a Sercrod expression. Therefore, when the connection name is a fixed name, write it as a string literal inside the HTML attribute.
Use *shadow="'messagebox'" and *host="'messagebox'". Do not write *shadow="messagebox" or *host="messagebox" when you mean the fixed name messagebox.
The outer double quotes are the HTML attribute quotes. The inner single quotes are part of the Sercrod expression.
<template *shadow="'messagebox'">
...
</template>
<message-box *host="'messagebox'">
...
</message-box>
This makes the relationship between the shadow template and the host clear for both humans and AI tools.
Use *shadow on the template side and *host on the host side.
Where to write *shadow
*shadow should be written on a <template> element.
Recommended:
<template *shadow="'messagebox'">
...
</template>
<message-box *host="'messagebox'">
...
</message-box>
Avoid writing *shadow directly on the host element:
<message-box *shadow>
...
</message-box>
Writing *shadow on the host element can make it look as if the host's children are moved into Shadow DOM, or as if the host itself becomes the shadow-side structure. That is not the intended model.
The shadow structure belongs in <template *shadow="'name'">. The host connection belongs on *host.
Connection name
The value of *shadow is the connection name used by *host.
<template *shadow="'profilecard'">
...
</template>
<profile-card *host="'profilecard'">
...
</profile-card>
In this example, profilecard is the connection name.
The recommended style is to write the same explicit name as a string literal on both sides:
*shadow="'profilecard'"on the template.*host="'profilecard'"on the host.
With value-less *host
A value-less *host is allowed as a shorthand, but it is not recommended.
<template *shadow="'MessageBox'">
...
</template>
<message-box *host>
...
</message-box>
When *host has no value, Sercrod derives a constructor-style connection name from the host element name.
message-box
->
MessageBox
Then Sercrod looks for <template *shadow="'MessageBox'">.
This shorthand is allowed, but explicit names are preferred because they are easier to read and harder to misunderstand.
Shadow template content
The shadow template should normally contain:
- Shadow-side structure.
- Shadow-side
<style>. - Standard
<slot>elements.
<template *shadow="'messagebox'">
<style>
:host {
display: block;
}
.message-box {
border: 1px solid #ccc;
padding: 1rem;
}
</style>
<section class="message-box">
<div class="message-box-title">
<slot name="title"></slot>
</div>
<div class="message-box-message">
<slot name="message"></slot>
</div>
</section>
</template>
In the initial specification, Sercrod directives inside the shadow template are not processed. Keep Sercrod data and binding directives on the Light DOM side unless a later feature explicitly enables shadow-side directive processing.
Use with *host
*shadow defines the template. *host consumes it.
<template *shadow="'profilecard'">
<section class="profile-card">
<header>
<slot name="name"></slot>
</header>
<main>
<slot name="body"></slot>
</main>
</section>
</template>
<profile-card *host="'profilecard'" data="{ first_name: `Taro`, last_name: `Yamada`, message: `Hello.` }">
<h2 slot="name" *let="full_name = `${last_name} ${first_name}`" *print="full_name"></h2>
<p slot="body" *print="message"></p>
</profile-card>
The Light DOM side can use normal Sercrod directives such as data, *let, and *print. The processed Light DOM content is then displayed at the slot positions by the browser's standard slot behavior.
CSS scope
Because *shadow uses the browser's standard Shadow DOM, CSS written inside the shadow template is scoped to that Shadow DOM.
Outer page CSS does not normally select elements inside the Shadow DOM with ordinary selectors. CSS written inside the shadow template does not leak out to the outer page.
This is useful for preview components, editor panels, and admin screens where the outer UI CSS and the preview layout CSS should be easier to keep apart.
<preview-box *host="'previewbox'">
<div class="same-box" slot="content">
<h2 class="same-title">Light DOM article title</h2>
<p class="same-body">Light DOM article body.</p>
</div>
</preview-box>
<template *shadow="'previewbox'">
<style>
.same-box {
border: 1px solid #ccc;
padding: 1rem;
}
.same-title {
font-size: 1.25rem;
}
.same-body {
line-height: 1.7;
}
</style>
<article class="same-box">
<header class="same-title">Shadow-side title frame</header>
<main class="same-body">
<slot name="content"></slot>
</main>
</article>
</template>
In this example, the same class names are used on both sides. Ordinary CSS selectors do not directly cross the Shadow DOM boundary.
Sercrod does not implement CSS isolation by itself. Sercrod connects the shadow template and the host element. CSS scoping is handled by the browser as part of standard Shadow DOM behavior.
Important note about slotted content
Slotted elements are still Light DOM nodes.
Even when they appear at a slot position inside the shadow layout, their actual nodes remain on the Light DOM side. Because of that, slotted elements may still be affected by outer page CSS.
If the preview content itself must be separated from the outer page CSS, render that content inside the Shadow DOM instead of passing it as slotted Light DOM content.
Behavior
- Sercrod collects
<template *shadow="'name'">elements. - Each shadow template is registered by name.
- When a host element refers to that name with
*host, Sercrod connects the host to the template. - If possible, Sercrod attaches an open Shadow DOM to the host.
- Sercrod clones the shadow template content into the host's shadow root.
- Standard slot assignment is handled by the browser.
- Light DOM children are not physically moved into the Shadow DOM.
Duplicate names
Do not define the same *shadow name more than once in the same effective registry.
<template *shadow="'messagebox'">
A
</template>
<template *shadow="'messagebox'">
B
</template>
This is not recommended.
The intended policy is:
- The first definition wins.
- Later duplicate definitions are ignored.
- Sercrod should emit a warning when warnings are enabled.
[Sercrod warn] duplicate *shadow template: messagebox
*shadow is a structure definition, not a CSS-like override rule. Later silent replacement would be harder for both humans and AI tools to follow.
Missing host
A *shadow template can exist before its host, after its host, or without an immediate host. The template itself only defines a reusable shadow structure.
If no host refers to the template, it simply produces no visible host output by itself.
What *shadow does not do
- It does not connect itself to a host without
*host. - It does not move Light DOM children into Shadow DOM.
- It does not reimplement slot assignment.
- It does not automatically add
<slot>elements. - It does not make the host element a full component renderer.
- It does not implement CSS isolation by itself.
Best practices
- Use
<template>as the*shadowhost. - Use explicit connection names as string literals whenever possible, such as
*shadow="'messagebox'"and*host="'messagebox'". - Keep shadow template content focused on structure, style, and slots.
- Put Sercrod data and binding directives on the Light DOM side.
- Use
*hoston the host element to connect to the template. - Avoid duplicate
*shadownames. - Remember that slotted content remains Light DOM content.
Notes
*shadowdefines a visible shadow template.*hostconnects a host element to a named shadow template.- Standard
<slot>andslot="..."behavior is handled by the browser. - CSS scoping is also standard Shadow DOM behavior.
- Sercrod's role is to connect the shadow template and the host element.