Skip to content

Commit

Permalink
feat(lightning-element): expose hostElement property (#4259)
Browse files Browse the repository at this point in the history
Co-authored-by: Nolan Lawson <[email protected]>
  • Loading branch information
rochejul and nolanlawson authored Jun 14, 2024
1 parent 228a4a7 commit 8b3f436
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 0 deletions.
19 changes: 19 additions & 0 deletions packages/@lwc/engine-core/src/framework/base-lightning-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
KEY__SYNTHETIC_MODE,
keys,
setPrototypeOf,
assert,
} from '@lwc/shared';

import { logError } from '../shared/logger';
Expand Down Expand Up @@ -194,6 +195,7 @@ export interface LightningElement extends HTMLElementTheGoodParts, AccessibleEle
constructor: LightningElementConstructor;
template: ShadowRoot | null;
refs: RefNodes | undefined;
hostElement: Element;
render(): Template;
connectedCallback?(): void;
disconnectedCallback?(): void;
Expand Down Expand Up @@ -542,6 +544,23 @@ function warnIfInvokedDuringConstruction(vm: VM, methodOrPropName: string) {
return vm.shadowRoot;
},

get hostElement(): Element {
const vm = getAssociatedVM(this);

if (!process.env.IS_BROWSER) {
assert.fail('this.hostElement is not supported in this environment');
}

if (process.env.NODE_ENV !== 'production') {
assert.isTrue(
vm.elm instanceof Element,
`this.hostElement should be an Element, found: ${vm.elm}`
);
}

return vm.elm;
},

get refs(): RefNodes | undefined {
const vm = getAssociatedVM(this);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this.hostElement is not supported in this environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const tagName = 'x-this-dot-host-element';
export { default } from 'x/this-dot-host-element';
export * from 'x/this-dot-host-element';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<span>{test}</span>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LightningElement } from 'lwc';

export default class ThisDotHostElement extends LightningElement {
constructor() {
super();
}

get test() {
return this.hostElement.tagName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createElement } from 'lwc';

import Wrapper from 'x/wrapper';

function createWrapper() {
const elm = createElement('x-wrapper', { is: Wrapper });
document.body.appendChild(elm);
return elm;
}

it('should provide the root element for light rendering', () => {
const elm = createWrapper();

const divElement = elm.getDivElement();
const lightElement = elm.getLightElement();
const hostElement = lightElement.getHostElement();

expect(hostElement).toBeTruthy();
expect(hostElement.tagName).toEqual('X-LIGHT');
expect(hostElement.dataset.name).toEqual('lightElement');

expect(hostElement).toEqual(lightElement);
expect(hostElement.parentElement).toEqual(divElement);
});

it('should provide the root element for shadow rendering', () => {
const elm = createWrapper();

const divElement = elm.getDivElement();
const shadowElement = elm.getShadowElement();
const hostElement = shadowElement.getHostElement();

expect(hostElement).toBeTruthy();
expect(hostElement.tagName).toEqual('X-SHADOW');
expect(hostElement.dataset.name).toEqual('shadowElement');

expect(hostElement).toEqual(shadowElement);
expect(hostElement.parentElement).toEqual(divElement);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<template lwc:render-mode="light"></template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LightningElement, api } from 'lwc';

export default class Light extends LightningElement {
static renderMode = 'light';

@api
getHostElement() {
return this.hostElement;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LightningElement, api } from 'lwc';

export default class Shadow extends LightningElement {
@api
getHostElement() {
return this.hostElement;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<template>
<div data-name="divElement" lwc:ref="div">
<x-light data-name="lightElement" lwc:ref="light"></x-light>
<x-shadow data-name="shadowElement" lwc:ref="shadow"></x-shadow>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { LightningElement, api } from 'lwc';

export default class Wrapper extends LightningElement {
@api
getDivElement() {
return this.refs.div;
}

@api
getLightElement() {
return this.refs.light;
}

@api
getShadowElement() {
return this.refs.shadow;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const expectedEnumerableProps = [
'hasAttribute',
'hasAttributeNS',
'hidden',
'hostElement',
'id',
'isConnected',
'lang',
Expand Down

0 comments on commit 8b3f436

Please sign in to comment.