From 6df5f719d148c66f6b7e5e48e13d283869719b29 Mon Sep 17 00:00:00 2001 From: Andrew Seier Date: Tue, 12 Nov 2024 14:47:19 -0800 Subject: [PATCH] Remove nullish coalescing for `textContent`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default browser behavior when setting `.textContent` to `null` or `undefined` is to ultimately set the content to `''`†. This is quite different from the behavior of `createTextNode` though… by splitting the text node creation into multiple steps we can consistently leverage `.textContent` and remove the need to `?? ''`. † Note that the WHATWG spec only defines that behavior for `null`, but in practice all modern browsers seem to treat `undefined` similarly. --- test/test-basic-properties.js | 13 ++++++++++++- x-element.js | 5 +++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/test/test-basic-properties.js b/test/test-basic-properties.js index a825ee9..bb88f20 100644 --- a/test/test-basic-properties.js +++ b/test/test-basic-properties.js @@ -23,6 +23,9 @@ class TestElement extends XElement { type: String, default: null, }, + undefinedProperty: { + type: String, + }, typelessProperty: {}, typelessPropertyWithCustomAttribute: { attribute: 'custom-attribute-typeless', @@ -33,12 +36,13 @@ class TestElement extends XElement { }; } static template(html) { - return ({ normalProperty, camelCaseProperty, numericProperty, nullProperty }) => { + return ({ normalProperty, camelCaseProperty, numericProperty, nullProperty, undefinedProperty }) => { return html`
${normalProperty}
${camelCaseProperty} ${numericProperty} ${nullProperty} + ${undefinedProperty} `; }; } @@ -60,6 +64,12 @@ it('renders an empty string in place of null value', () => { assert(el.shadowRoot.getElementById('nul').textContent === ''); }); +it('renders an empty string in place of undefined value', () => { + const el = document.createElement('test-element'); + document.body.append(el); + assert(el.shadowRoot.getElementById('undef').textContent === ''); +}); + it('property setter updates on next micro tick after connect', async () => { const el = document.createElement('test-element'); el.camelCaseProperty = 'Nonconforming'; @@ -99,6 +109,7 @@ it('observes all dash-cased versions of public, typeless, serializable, and decl 'camel-case-property', 'numeric-property', 'null-property', + 'undefined-property', 'typeless-property', 'custom-attribute-typeless', ]; diff --git a/x-element.js b/x-element.js index 2dfb52f..10627e7 100644 --- a/x-element.js +++ b/x-element.js @@ -1488,10 +1488,11 @@ class TemplateEngine { } const previousSibling = node.previousSibling; if (previousSibling === startNode) { - const textNode = document.createTextNode(value ?? ''); + const textNode = document.createTextNode(''); + textNode.textContent = value; node.parentNode.insertBefore(textNode, node); } else { - previousSibling.textContent = value ?? ''; + previousSibling.textContent = value; } } }