Skip to content

Commit 65bc240

Browse files
authored
[labs/ssr-dom-shim] Patch localName and tagName with customElements.define call (#4553)
1 parent 9217527 commit 65bc240

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

.changeset/lovely-suits-rescue.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@lit-labs/ssr-dom-shim': patch
3+
---
4+
5+
Implement Element.localName and Element.tagName. Fixes [3375](https://github.com/lit/lit/issues/3375).

packages/labs/ssr-dom-shim/src/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ const ElementShim = class Element {
5353
}
5454
return this.__shadowRoot;
5555
}
56+
get localName() {
57+
return (this.constructor as NamedCustomHTMLElementConstructor).__localName;
58+
}
59+
get tagName() {
60+
return this.localName?.toUpperCase();
61+
}
5662
setAttribute(name: string, value: unknown): void {
5763
// Emulate browser behavior that silently casts all values to string. E.g.
5864
// `42` becomes `"42"` and `{}` becomes `"[object Object]""`.
@@ -123,6 +129,11 @@ interface CustomHTMLElementConstructor {
123129
observedAttributes?: string[];
124130
}
125131

132+
interface NamedCustomHTMLElementConstructor
133+
extends CustomHTMLElementConstructor {
134+
__localName: string;
135+
}
136+
126137
type CustomElementRegistration = {
127138
ctor: {new (): HTMLElement};
128139
observedAttributes: string[];
@@ -148,6 +159,8 @@ const CustomElementRegistryShim = class CustomElementRegistry {
148159
);
149160
}
150161
}
162+
// Provide tagName and localName for the component.
163+
(ctor as NamedCustomHTMLElementConstructor).__localName = name;
151164
this.__definitions.set(name, {
152165
ctor,
153166
// Note it's important we read `observedAttributes` in case it is a getter

packages/labs/ssr-dom-shim/src/test/element-shim_test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import {suite} from 'uvu';
88
// eslint-disable-next-line import/extensions
99
import * as assert from 'uvu/assert';
10-
import {HTMLElement} from '@lit-labs/ssr-dom-shim';
10+
import {customElements, HTMLElement} from '@lit-labs/ssr-dom-shim';
1111

1212
const test = suite('Element Shim');
1313

@@ -45,4 +45,32 @@ test('setAttribute silently casts values to a string', () => {
4545
assert.equal(shimmedEl.getAttribute('tomato'), '[object Object]');
4646
});
4747

48+
test('localName and tagName should be available with constructor from customElements registry', () => {
49+
const elementName = 'lit-test-registry';
50+
customElements.define(elementName, class extends HTMLElement {});
51+
const LitTestRegistry = customElements.get(elementName)!;
52+
53+
const shimmedEl = new LitTestRegistry();
54+
assert.equal(shimmedEl.localName, elementName);
55+
assert.equal(shimmedEl.tagName, elementName.toUpperCase());
56+
});
57+
58+
test('localName and tagName should be available when registering with customElements', () => {
59+
const elementName = 'lit-test-local';
60+
class LitTestLocal extends HTMLElement {}
61+
customElements.define(elementName, LitTestLocal);
62+
63+
const shimmedEl = new LitTestLocal();
64+
assert.equal(shimmedEl.localName, elementName);
65+
assert.equal(shimmedEl.tagName, elementName.toUpperCase());
66+
});
67+
68+
test('localName and tagName usage should return undefined if not registered', () => {
69+
class LitTestUnregistered extends HTMLElement {}
70+
71+
const shimmedEl = new LitTestUnregistered();
72+
assert.equal(shimmedEl.localName, undefined);
73+
assert.equal(shimmedEl.tagName, undefined);
74+
});
75+
4876
test.run();

0 commit comments

Comments
 (0)