[Bug] `#in-element` cannot directly render in to shadow-dom
- Dominant language
- TypeScript
- Stars
- 22.6k
- Forks
- 4.2k
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 15
Description
### 🐞 Describe the Bug
### 😕 Actual Behavior
```glimmer-ts
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { modifier } from 'ember-modifier';
const attachShadow = modifier((element: Element, [set]: [(shadowRoot: ShadowRoot) => void]) => {
let shadow = element.attachShadow({ mode: 'open' });
set(shadow);
});
// index.html has the production-fingerprinted references to these links
// Ideally, we'd have some pre-processor scan everything for references to
// assets in public, but idk how to set that up
const getStyles = () => [...document.head.querySelectorAll('link')].map((link) => link.href);
export class Shadowed extends Component<{
Element: HTMLDivElement;
Args: {
omitStyles?: boolean;
};
Blocks: { default: [] };
}> {
@tracked shadow: ShadowRoot | undefined;
setShadow = async (shadowRoot: ShadowRoot) => {
await Promise.resolve();
this.shadow = shadowRoot;
}
{{#if this.shadow}}
{{#in-element this.shadow}}
{{#unless @omitStyles}}
{{#each (getStyles) as |styleHref|}}
{{/each}}
{{/unless}}
{{yield}}
{{/in-element}}
{{/if}}
}
export default Shadowed;
```
Used in this test:
```gts
import { find, render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { Shadowed } from 'limber/components/shadowed';
module('Rendering | ', function (hooks) {
setupRenderingTest(hooks);
test('it works', async function (assert) {
await render(
out of shadow
in shadow
);
assert.dom().hasText('out of shadow');
assert.dom().doesNotContainText('in shadow');
// assort.dom forgot that ShadowDom is a thing
// assert.dom(find('[data-shadow]')?.shadowRoot).hasText('in shadow');
assert.ok(find('[data-shadow]')?.shadowRoot?.textContent?.includes('in shadow'));
});
});
```
Causes this error:
```
Error occurred:
- While rendering:
-top-level
application
index
_shadowedTest
Shadowed
[runtime.js:5723](http://localhost:4201/assets/@glimmer/runtime.js)
Error occurred:
[runtime.js:4948](http://localhost:4201/assets/@glimmer/runtime.js)
Uncaught (in promise) Error: Got [object ShadowRoot], expected:
{ nodeType: 1,tagName: typeof string,nextSibling: any }
check debug.js:1512 # @glimmer/debug
runtime.js:1508
evaluate runtime.js:1061
```
and doesn't actually render in to the shadow dom:

### 🤔 Expected Behavior
A clear and concise description of what you expected to happen.
### 🌍 Environment
- Ember: - 5.5, 5.6+
- Node.js/npm: -
- OS: -
- Browser: - Firefox
I was able to get desired behavior at the cost of an extra div here:
```glimmer-ts
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { modifier } from 'ember-modifier';
const attachShadow = modifier((element: Element, [set]: [(shadowRoot: HTMLDivElement) => void]) => {
let shadow = element.attachShadow({ mode: 'open' });
let div = document.createElement('div');
shadow.appendChild(div);
set(div);
});
// index.html has the production-fingerprinted references to these links
// Ideally, we'd have some pre-processor scan everything for references to
// assets in public, but idk how to set that up
const getStyles = () => [...document.head.querySelectorAll('link')].map((link) => link.href);
export class Shadowed extends Component<{
Element: HTMLDivElement;
Args: {
omitStyles?: boolean;
};
Blocks: { default: [] };
}> {
@tracked shadow: HTMLDivElement | undefined;
setShadow = async (shadowRoot: HTMLDivElement) => {
await Promise.resolve();
this.shadow = shadowRoot;
}
{{#if this.shadow}}
{{#in-element this.shadow}}
{{#unless @omitStyles}}
{{#each (getStyles) as |styleHref|}}
{{/each}}
{{/unless}}
{{yield}}
{{/in-element}}
{{/if}}
}
export default Shadowed;
```
(this change also makes the test pass, but again, at the cost of an extra div)
Contributor guide
Assessment
This issue has not been assessed yet.