diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts
index ef5051f42f7..6b9f7d1391e 100644
--- a/packages/runtime-dom/__tests__/customElement.spec.ts
+++ b/packages/runtime-dom/__tests__/customElement.spec.ts
@@ -1386,4 +1386,39 @@ describe('defineCustomElement', () => {
await nextTick()
expect(e.shadowRoot!.innerHTML).toBe(`false,boolean`)
})
+
+ test('hyphenated attr removal', async () => {
+ const E = defineCustomElement({
+ props: {
+ fooBar: {
+ type: Boolean,
+ },
+ },
+ render() {
+ return this.fooBar
+ },
+ })
+ customElements.define('el-hyphenated-attr-removal', E)
+ const toggle = ref(true)
+ const Comp = {
+ render() {
+ return h('el-hyphenated-attr-removal', {
+ 'foo-bar': toggle.value ? '' : null,
+ })
+ },
+ }
+ render(h(Comp), container)
+ const el = container.children[0]
+ expect(el.hasAttribute('foo-bar')).toBe(true)
+ expect((el as any).outerHTML).toBe(
+ ``,
+ )
+
+ toggle.value = false
+ await nextTick()
+ expect(el.hasAttribute('foo-bar')).toBe(false)
+ expect((el as any).outerHTML).toBe(
+ ``,
+ )
+ })
})
diff --git a/packages/runtime-dom/src/modules/props.ts b/packages/runtime-dom/src/modules/props.ts
index 93d45c9e160..98608831a9a 100644
--- a/packages/runtime-dom/src/modules/props.ts
+++ b/packages/runtime-dom/src/modules/props.ts
@@ -8,6 +8,7 @@ export function patchDOMProp(
key: string,
value: any,
parentComponent: any,
+ attrName?: string,
): void {
// __UNSAFE__
// Reason: potentially setting innerHTML.
@@ -106,5 +107,5 @@ export function patchDOMProp(
)
}
}
- needRemove && el.removeAttribute(key)
+ needRemove && el.removeAttribute(attrName || key)
}
diff --git a/packages/runtime-dom/src/patchProp.ts b/packages/runtime-dom/src/patchProp.ts
index 5814e77c4f8..b6af8997112 100644
--- a/packages/runtime-dom/src/patchProp.ts
+++ b/packages/runtime-dom/src/patchProp.ts
@@ -62,7 +62,7 @@ export const patchProp: DOMRendererOptions['patchProp'] = (
(el as VueElement)._isVueCE &&
(/[A-Z]/.test(key) || !isString(nextValue))
) {
- patchDOMProp(el, camelize(key), nextValue, parentComponent)
+ patchDOMProp(el, camelize(key), nextValue, parentComponent, key)
} else {
// special case for with
// :true-value & :false-value