Visitar URL original
fix(compiler-vapor): keep end tags inside and around form elements by ondrhn · Pull Request #15693 · vuejs/core · GitHub
Skip to content

fix(compiler-vapor): keep end tags inside and around form elements - #15693

Merged
edison1105 merged 1 commit into
vuejs:minorfrom
ondrhn:fix/issue-15691-compiler-vapor-keep-end-tags
Sep 28, 2026
Merged

edison1105 merged 1 commit into
vuejs:minorfrom
ondrhn:fix/issue-15691-compiler-vapor-keep-end-tags

Conversation

@ondrhn

@ondrhn ondrhn commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

A Vapor template that puts an element inside a <form> renders the wrong tree. For
<section><form><div>x</div></form><p>y</p></section> the compiler emits
<section><form><div>x</form><p>y, and the parser puts the <p> inside the form's <div> instead of
after the form. In <div><form>...</form></div><div><form>...</form></div> the second <form> start tag is
dropped while its children stay. When a binding follows the form, the render function takes next(form),
gets null and mounting throws Cannot read properties of null (reading 'firstChild'). Only
client-created trees are affected. Hydration adopts the server DOM and parses no template string.

template() builds the DOM from an HTML string, where shipping parsers route form through the form
element pointer: </form> removes the form element alone rather than popping up to it, so a descendant
whose end tag was omitted stays open and adopts the form's next sibling; and a form closed by its parent's
end tag leaves the pointer set, which makes the parser ignore the next <form> start tag. canOmitEndTag
in transforms/transformElement.ts accounted for neither, so it dropped the end tag of the form's last
child. This adds form to ALWAYS_CLOSE_TAGS in shared/src/domTagConfig.ts so a form off the rightmost
path keeps its end tag and resets the pointer, and makes canOmitEndTag keep the end tag of every element
inside a form whose end tag is emitted. A form on the rightmost path still omits as before; the cost is a
few extra end tags inside forms that are not. The fix is correct under both the old parse rule and
whatwg/html#12911.

This is the mechanism of #14336, which 3d550db (#14337) fixed only for a <button> as the form's last
child; #15657 covers the same class for foreign content. Fix proposed by @denismrte in #15691.

fix #15691

`</form>` goes through the form element pointer and removes only the form
element itself, so an element inside a form whose end tag is emitted has to
close itself. `form` is added to ALWAYS_CLOSE_TAGS so a form off the rightmost
path keeps its end tag and resets the pointer for the next form.

fix vuejs#15691
@coderabbitai

coderabbitai Bot commented Sep 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 6c576340-3ba9-4af4-8d91-33c940b6229a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Sep 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@15693
npm i https://pkg.pr.new/@vue/compiler-core@15693
yarn add https://pkg.pr.new/@vue/compiler-core@15693.tgz

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@15693
npm i https://pkg.pr.new/@vue/compiler-dom@15693
yarn add https://pkg.pr.new/@vue/compiler-dom@15693.tgz

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@15693
npm i https://pkg.pr.new/@vue/compiler-sfc@15693
yarn add https://pkg.pr.new/@vue/compiler-sfc@15693.tgz

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@15693
npm i https://pkg.pr.new/@vue/compiler-ssr@15693
yarn add https://pkg.pr.new/@vue/compiler-ssr@15693.tgz

@vue/compiler-vapor

pnpm add https://pkg.pr.new/@vue/compiler-vapor@15693
npm i https://pkg.pr.new/@vue/compiler-vapor@15693
yarn add https://pkg.pr.new/@vue/compiler-vapor@15693.tgz

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@15693
npm i https://pkg.pr.new/@vue/reactivity@15693
yarn add https://pkg.pr.new/@vue/reactivity@15693.tgz

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@15693
npm i https://pkg.pr.new/@vue/runtime-core@15693
yarn add https://pkg.pr.new/@vue/runtime-core@15693.tgz

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@15693
npm i https://pkg.pr.new/@vue/runtime-dom@15693
yarn add https://pkg.pr.new/@vue/runtime-dom@15693.tgz

@vue/runtime-vapor

pnpm add https://pkg.pr.new/@vue/runtime-vapor@15693
npm i https://pkg.pr.new/@vue/runtime-vapor@15693
yarn add https://pkg.pr.new/@vue/runtime-vapor@15693.tgz

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@15693
npm i https://pkg.pr.new/@vue/server-renderer@15693
yarn add https://pkg.pr.new/@vue/server-renderer@15693.tgz

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@15693
npm i https://pkg.pr.new/@vue/shared@15693
yarn add https://pkg.pr.new/@vue/shared@15693.tgz

vue

pnpm add https://pkg.pr.new/vue@15693
npm i https://pkg.pr.new/vue@15693
yarn add https://pkg.pr.new/vue@15693.tgz

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@15693
npm i https://pkg.pr.new/@vue/compat@15693
yarn add https://pkg.pr.new/@vue/compat@15693.tgz

commit: 6c4d146

@github-actions

Copy link
Copy Markdown

Size Report

Bundles

File Size Gzip Brotli
compiler-dom.global.prod.js 87.2 kB 30.6 kB 26.9 kB
runtime-dom.global.prod.js 116 kB 43.9 kB 39.2 kB
vue.global.prod.js 176 kB 64 kB 57 kB

Usages

Name Size Gzip Brotli
createApp (CAPI only) 53.1 kB 20.7 kB 18.9 kB
createApp 61.9 kB 23.9 kB 21.7 kB
createApp + vaporInteropPlugin 125 kB 45.1 kB 40.6 kB
createVaporApp 31.3 kB 12 kB 11 kB
createSSRApp 66.9 kB 25.9 kB 23.6 kB
createVaporSSRApp 37.9 kB 14.4 kB 13.2 kB
defineCustomElement 68.4 kB 25.9 kB 23.5 kB
defineVaporCustomElement 46.7 kB 17 kB 15.6 kB
overall 77.4 kB 29.4 kB 26.7 kB

@edison1105
edison1105 merged commit 65919d9 into vuejs:minor Sep 28, 2026
15 checks passed
zhiyuanzmj added a commit to vuejs/vue-jsx-vapor that referenced this pull request Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants