-
Notifications
You must be signed in to change notification settings - Fork 816
Description
Prerequisites
- I have read the Contributing Guidelines.
- I agree to follow the Code of Conduct.
- I have searched for existing issues that already report this problem, without success.
Stencil Version
4.35.0
Current Behavior
We have used StencilJS extensively to build up a component library for our company. Now, as we are integrating them into our web-site, we consistently running in some issues, namely that sometimes (randomly!) Stencil fails to slot children correctly initially.
We are using scoped web-components (without shadow-dom) and all slot-fixes applied, as well as the "dist-custom-elements" target. This issue seems to appear with named and un-named slots with nearly all components, whether they are a complex or simple containers.
Here you can see, how the right-most component does not render correctly as the others.
Here the malformed HTML:
<option-picker name="chip-1" legend="Speichergröße" align="start" class="hydrated"><!---->
<fieldset id="fca9de69-f131-49ae-b5b4-491eaa8ec050" class="option-picker layout-spacing-medium align-start">
<legend class="option-picker__legend">Speichergröße</legend>
<div class="option-picker__label" aria-hidden="true">Speichergröße<span
class="option-picker__label__value-text"></span></div>
<div class="option-picker__options"></div>
</fieldset>
<option-picker-item value="option-1" variant="chip" class="hydrated"><!---->
<div class="option-picker-item variant-chip"><label class="option-picker-item__label"
for="907e8ca6-bc95-4e40-b566-4d10d217b515"></label><input id="907e8ca6-bc95-4e40-b566-4d10d217b515"
class="option-picker-item__input" name="chip-1" type="radio" value="option-1"><span class="focus-indicator"
aria-hidden="true"></span></div>128 GB
</option-picker-item>
<option-picker-item value="option-2" variant="chip" class="hydrated"><!---->
<div class="option-picker-item variant-chip"><label class="option-picker-item__label"
for="cb6c1352-a984-49a4-a844-9b5d4cb117e4">256 GB</label><input id="cb6c1352-a984-49a4-a844-9b5d4cb117e4"
class="option-picker-item__input" name="chip-1" type="radio" value="option-2"><span class="focus-indicator"
aria-hidden="true"></span></div>
</option-picker-item>
<option-picker-item value="option-3" variant="chip" class="hydrated"><!---->
<div class="option-picker-item variant-chip"><label class="option-picker-item__label"
for="df1b4100-a9af-4ba5-9144-819705125614">512 GB</label><input id="df1b4100-a9af-4ba5-9144-819705125614"
class="option-picker-item__input" name="chip-1" type="radio" value="option-3"><span class="focus-indicator"
aria-hidden="true"></span></div>
</option-picker-item>
</option-picker>
Each option-picker-item element is supposed to be slotted into fieldset div "option-picker__options".
A re-render appears to solve the problem, such as when the user interacts with the component and causes a re-render. As such, our current workaround is to set a timeout (~20ms) in the "componentDidLoad" lifecycle method, which then sets a flag (annotated with @State) to trigger a re-render.
However, this is not an ideal solution, and small enough timeouts appear to also fail in some cases. We suspect there might be some race-condition in the shadow-dom polyfill or rendering logic.
Expected Behavior
Stencils slots all children correctly.
The expected HTML in our case would be
<option-picker name="chip-2" class="hydrated"><!----><span slot="legend" hidden="">Speichergröße</span>
<fieldset id="c19a62ca-6a39-43a2-99e1-9596d91ac11d" class="option-picker layout-spacing-medium align-center">
<div class="option-picker__options">
<option-picker-item value="option-1" variant="chip" class="hydrated"><!---->
<div class="option-picker-item variant-chip"><label class="option-picker-item__label"
for="2ec7153b-28e4-4d81-906a-78a1447dcfe5">128 GB</label><input id="2ec7153b-28e4-4d81-906a-78a1447dcfe5"
class="option-picker-item__input" name="chip-2" type="radio" value="option-1"><span class="focus-indicator"
aria-hidden="true"></span></div>
</option-picker-item>
<option-picker-item value="option-2" variant="chip" class="hydrated"><!---->
<div class="option-picker-item variant-chip"><label class="option-picker-item__label"
for="00dd93d9-529f-46e5-a932-67b8f04eb17d">256 GB</label><input id="00dd93d9-529f-46e5-a932-67b8f04eb17d"
class="option-picker-item__input" name="chip-2" type="radio" value="option-2"><span class="focus-indicator"
aria-hidden="true"></span></div>
</option-picker-item>
<option-picker-item value="option-3" variant="chip" class="hydrated"><!---->
<div class="option-picker-item variant-chip"><label class="option-picker-item__label"
for="672c55bc-07d5-4fa2-bab9-9966689740b5">512 GB</label><input id="672c55bc-07d5-4fa2-bab9-9966689740b5"
class="option-picker-item__input" name="chip-2" type="radio" value="option-3"><span class="focus-indicator"
aria-hidden="true"></span></div>
</option-picker-item>
</div>
</fieldset>
</option-picker>
System Info
System: node 20.10.0
Platform: darwin (24.0.0)
CPU Model: Apple M2 (8 cpus)
Compiler: <private>/node_modules/.pnpm/@[email protected]/node_modules/@stencil/core/compiler/stencil.js
Build: 1749776174
Stencil: 4.35.0 🌝
TypeScript: 5.5.4
Rollup: 4.34.9
Parse5: 7.2.1
jQuery: 4.0.0-pre
Terser: 5.37.0
The problem could not be reproduced on MacOS, but rather on Windows machines in the Chrome, Edge, and FireFox browsers.
Steps to Reproduce
Create a web-component with slots (nested within some divs).
Then render this component multiple times with children (to increase the chance of the error to occur). Sometimes, this bug will occur, and page-refreshes might be necessary to finally see the error.
We use this config:
export const config: Config = {
namespace: 'gucci-common-web-components',
outputTargets: [
{
type: 'dist-custom-elements',
customElementsExportBehavior: 'bundle',
externalRuntime: false
},
{
type: 'dist-hydrate-script',
dir: '.dist-hydrate'
},
{
type: 'docs-json',
file: 'dist/docs/component-docs.json',
}
],
extras: {
experimentalSlotFixes: true,
experimentalScopedSlotChanges: true
}
};
Code Reproduction URL
Additional Information
No response