diff --git a/packages/runtime-dom/__tests__/patchProps.spec.ts b/packages/runtime-dom/__tests__/patchProps.spec.ts index 687b2b79056..962d55e882b 100644 --- a/packages/runtime-dom/__tests__/patchProps.spec.ts +++ b/packages/runtime-dom/__tests__/patchProps.spec.ts @@ -145,5 +145,8 @@ describe('runtime-dom: props patching', () => { // non existant element expect(el.form).toBe(null) expect(el.getAttribute('form')).toBe('foo') + // remove attribute + patchProp(el, 'form', 'foo', null) + expect(el.getAttribute('form')).toBe(null) }) }) diff --git a/packages/runtime-dom/src/patchProp.ts b/packages/runtime-dom/src/patchProp.ts index 91f6ed526dc..848ee160a8b 100644 --- a/packages/runtime-dom/src/patchProp.ts +++ b/packages/runtime-dom/src/patchProp.ts @@ -3,7 +3,13 @@ import { patchStyle } from './modules/style' import { patchAttr } from './modules/attrs' import { patchDOMProp } from './modules/props' import { patchEvent } from './modules/events' -import { isOn, isString, isFunction, isModelListener } from '@vue/shared' +import { + isOn, + isString, + isFunction, + isModelListener, + isFormTag +} from '@vue/shared' import { RendererOptions } from '@vue/runtime-core' const nativeOnRE = /^on[a-z]/ @@ -93,9 +99,9 @@ function shouldSetAsProp( return false } - // #1787 form as an attribute must be a string, while it accepts an Element as - // a prop - if (key === 'form' && typeof value === 'string') { + // #1787, #2840 the form property is readonly and can only be set as an + // attribute using a string value + if (key === 'form' && isFormTag(el.tagName)) { return false } diff --git a/packages/shared/src/domTagConfig.ts b/packages/shared/src/domTagConfig.ts index bbacdc12535..d18e392b55b 100644 --- a/packages/shared/src/domTagConfig.ts +++ b/packages/shared/src/domTagConfig.ts @@ -30,6 +30,11 @@ const SVG_TAGS = const VOID_TAGS = 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr' +const FORM_TAGS = + 'button,datalist,fieldset,input,keygen,label,legend,meter,optgroup,option,' + + 'output,progress,select,textarea' + export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS) export const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS) export const isVoidTag = /*#__PURE__*/ makeMap(VOID_TAGS) +export const isFormTag = /*#__PURE__*/ makeMap(FORM_TAGS, true)