diff --git a/src/index.js b/src/index.js index 6035643..42318d7 100644 --- a/src/index.js +++ b/src/index.js @@ -90,6 +90,11 @@ function toCamelCase(str) { function attributeChangedCallback(name, oldValue, newValue) { if (!this._vdom) return; + // Attributes use `null` as an empty value whereas `undefined` is more + // common in pure JS components, especially with default parameters. + // When calling `node.removeAttribute()` we'll receive `null` as the new + // value. See issue #50. + newValue = newValue == null ? undefined : newValue; const props = {}; props[name] = newValue; props[toCamelCase(name)] = newValue; diff --git a/src/index.test.jsx b/src/index.test.jsx index 77b5b2d..00da646 100644 --- a/src/index.test.jsx +++ b/src/index.test.jsx @@ -40,6 +40,21 @@ describe('web components', () => { ); }); + function NullProps({ size = 'md' }) { + return
{size.toUpperCase()}
; + } + + registerElement(NullProps, 'x-null-props', ['size'], { shadow: true }); + + // #50 + it('remove attributes without crashing', () => { + const el = document.createElement('x-null-props'); + assert.doesNotThrow(() => (el.size = 'foo')); + root.appendChild(el); + + assert.doesNotThrow(() => el.removeAttribute('size')); + }); + describe('DOM properties', () => { it('passes property changes to props', () => { const el = document.createElement('x-clock');