Skip to content

Commit 8b97be0

Browse files
Fix crash with empty attribute values
Attributes use null as the empty value whereas undefined is more common with JavaScript. The latter is necessary to make default parameter values work.
1 parent 9aff394 commit 8b97be0

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

src/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ function toCamelCase(str) {
9090

9191
function attributeChangedCallback(name, oldValue, newValue) {
9292
if (!this._vdom) return;
93+
// Attributes use `null` as an empty value whereas `undefined` is more
94+
// common in pure JS components, especially with default parameters.
95+
// When calling `node.removeAttribute()` we'll receive `null` as the new
96+
// value. See issue #50.
97+
newValue = newValue == null ? undefined : newValue;
9398
const props = {};
9499
props[name] = newValue;
95100
props[toCamelCase(name)] = newValue;

src/index.test.jsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ describe('web components', () => {
4040
);
4141
});
4242

43+
function NullProps({ size = 'md' }) {
44+
return <div>{size.toUpperCase()}</div>;
45+
}
46+
47+
registerElement(NullProps, 'x-null-props', ['size'], { shadow: true });
48+
49+
// #50
50+
it('remove attributes without crashing', () => {
51+
const el = document.createElement('x-null-props');
52+
assert.doesNotThrow(() => (el.size = 'foo'));
53+
root.appendChild(el);
54+
55+
assert.doesNotThrow(() => el.removeAttribute('size'));
56+
});
57+
4358
describe('DOM properties', () => {
4459
it('passes property changes to props', () => {
4560
const el = document.createElement('x-clock');

0 commit comments

Comments
 (0)