fix(custom-element): enhance slot handling with `shadowRoot:false`
close #13206 close #13234
Note
This PR only fixed bugs in the optimized mode, while issues still exist in the full diff scenario. This happens because _renderSlots only renders slots that have corresponding outlets, meaning not all slots in this._slots are rendered to the DOM tree. During full diff, parent.insertBefore(node, anchor) throws an error because the anchor node isn't actually in the DOM tree.
I couldn't find a suitable solution, so rolled back the full diff related code in 3e724095072d6ae4f8b095e6fc0eb25eb1564f67
Summary by CodeRabbit
Summary by CodeRabbit
- New Features
- Enhanced support for Vue custom elements without Shadow DOM, improving slot fallback content management and dynamic slot updates.
- Bug Fixes
- Fixed element mounting and slot updating issues for custom elements with
shadowRoot: false, ensuring correct DOM insertion and slot rendering.
- Fixed element mounting and slot updating issues for custom elements with
- Tests
- Added extensive tests covering slot updates, fallback content, and conditional rendering in custom elements without Shadow DOM for improved stability.
Size Report
Bundles
| File | Size | Gzip | Brotli |
|---|---|---|---|
| runtime-dom.global.prod.js | 102 kB (+1.45 kB) | 38.6 kB (+412 B) | 34.8 kB (+358 B) |
| vue.global.prod.js | 160 kB (+1.45 kB) | 58.8 kB (+404 B) | 52.3 kB (+378 B) |
Usages
| Name | Size | Gzip | Brotli |
|---|---|---|---|
| createApp (CAPI only) | 46.6 kB (+74 B) | 18.2 kB (+38 B) | 16.7 kB (+31 B) |
| createApp | 54.6 kB (+74 B) | 21.2 kB (+39 B) | 19.4 kB (+41 B) |
| createSSRApp | 58.8 kB (+74 B) | 23 kB (+34 B) | 21 kB (+40 B) |
| defineCustomElement | 60.7 kB (+1.45 kB) | 23.2 kB (+426 B) | 21.1 kB (+338 B) |
| overall | 68.6 kB (+74 B) | 26.4 kB (+41 B) | 24 kB (+41 B) |
@vue/compiler-core
npm i https://pkg.pr.new/@vue/compiler-core@13208
@vue/compiler-dom
npm i https://pkg.pr.new/@vue/compiler-dom@13208
@vue/compiler-sfc
npm i https://pkg.pr.new/@vue/compiler-sfc@13208
@vue/compiler-ssr
npm i https://pkg.pr.new/@vue/compiler-ssr@13208
@vue/runtime-core
npm i https://pkg.pr.new/@vue/runtime-core@13208
@vue/reactivity
npm i https://pkg.pr.new/@vue/reactivity@13208
@vue/runtime-dom
npm i https://pkg.pr.new/@vue/runtime-dom@13208
@vue/server-renderer
npm i https://pkg.pr.new/@vue/server-renderer@13208
@vue/shared
npm i https://pkg.pr.new/@vue/shared@13208
vue
npm i https://pkg.pr.new/vue@13208
@vue/compat
npm i https://pkg.pr.new/@vue/compat@13208
commit: 3e72409
Hi @edison1105, thanks for this fix, it works well with Vue 3.
However it doesn't work if we create custom elements from Vue 3 components and use them in Vue 2 or React wrapping with Vue 2 or React component similarly as I did in reproduction playground (see CEWrapperOne) . To provide more context: here is a schema of what we are working on at the moment. So we are creating a component library based on Vue 3 but to reuse this implementation in different applications written in Vue 2 or React we use custom elements created from Vue 3 components implementation.
@wolandec I also found some issues in other scenarios and haven't found a good solution yet, so the PR is still in Draft status.
@edison1105 thanks for the clarification, I'll prepare a reproduction repo for our case if it helps.
@edison1105 https://github.com/wolandec/vue-core-issue-13206 Here is the repository with the reproduction of our case of using, I hope it helps. Please let me know if you need any help, thank you!
"""
Walkthrough
The changes introduce enhanced support for Vue custom elements using shadowRoot: false, focusing on correct slot and conditional rendering behavior. Core renderer logic, slot parsing, and DOM patching are updated, and new tests are added to verify slot fallback and v-if/v-show handling in custom elements without shadow DOM.
Changes
| File(s) | Change Summary |
|---|---|
| packages/runtime-core/src/renderer.ts | Modified element mounting and patching logic to handle Vue custom elements with shadowRoot: false, including container reassignment, slot updates via _updateSlots, and fallback handling in patchBlockChildren. |
| packages/runtime-dom/src/apiCustomElement.ts | Enhanced slot management for custom elements without shadow DOM: introduced _slotFallbacks, _slotAnchors, and modified _slots properties; added _updateSlots, _parseSlotFallbacks methods; improved fallback slot capturing and rendering; adjusted slot parsing to retain parent references; added helpers for DOM insertion and node collection; updated cleanup in disconnectedCallback. |
| packages/runtime-dom/tests/customElement.spec.ts | Added tests for custom elements with shadowRoot: false to verify correct slot fallback, conditional rendering (v-if), and slot content switching, both with optimized and standard rendering modes. No changes to existing logic. |
Sequence Diagram(s)
sequenceDiagram
participant Host as Host App
participant VueCE as Vue Custom Element (shadowRoot: false)
participant Renderer as Renderer
participant DOM as DOM
Host->>VueCE: Insert slotted content (with v-if/v-show)
VueCE->>Renderer: Mount element
Renderer->>VueCE: Call _parseSlotFallbacks and _renderSlots
VueCE->>DOM: Insert anchor and slot/fallback content
Host->>VueCE: Update reactive state (e.g., v-if toggles)
VueCE->>Renderer: Patch element
Renderer->>VueCE: Call _updateSlots (oldVNode, newVNode)
VueCE->>DOM: Update slot content or fallback as needed
Assessment against linked issues
| Objective | Addressed | Explanation |
|---|---|---|
Correctly render and update slotted content with v-if/v-show in custom elements ( #13206 ) |
✅ | |
Prevent errors and ensure named slot content with v-if works without exceptions ( #13234 ) |
✅ |
Poem
In the garden of slots, where the shadows don’t grow,
The v-if and v-show now shimmer and glow.
Fallbacks and anchors, a bunny’s delight,
No more null errors in the custom element night!
🐇✨
Hop-hop—slots fixed just right! """
[!TIP]
⚡️ Faster reviews with caching
- CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure
Review - Disable Cacheat either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off theData Retentionsetting under your Organization Settings.Enjoy the performance boost—your workflow just got faster.
✨ Finishing Touches
- [ ] 📝 Generate Docstrings
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
I pushed a fix in commit <commit_id>, please review it.Explain this complex logic.Open a follow-up GitHub issue for this discussion.
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. Examples:@coderabbitai explain this code block.@coderabbitai modularize this function.
- PR comments: Tag
@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.@coderabbitai read src/utils.ts and explain its main purpose.@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.@coderabbitai help me debug CodeRabbit configuration file.
Support
Need help? Create a ticket on our support page for assistance with any issues or questions.
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.
CodeRabbit Commands (Invoked using PR comments)
@coderabbitai pauseto pause the reviews on a PR.@coderabbitai resumeto resume the paused reviews.@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository.@coderabbitai full reviewto do a full review from scratch and review all the files again.@coderabbitai summaryto regenerate the summary of the PR.@coderabbitai generate docstringsto generate docstrings for this PR.@coderabbitai generate sequence diagramto generate a sequence diagram of the changes in this PR.@coderabbitai resolveresolve all the CodeRabbit review comments.@coderabbitai configurationto show the current CodeRabbit configuration for the repository.@coderabbitai helpto get help.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
CodeRabbit Configuration File (.coderabbit.yaml)
- You can programmatically configure CodeRabbit by adding a
.coderabbit.yamlfile to the root of your repository. - Please see the configuration documentation for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation:
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
Documentation and Community
- Visit our Documentation for detailed information on how to use CodeRabbit.
- Join our Discord Community to get help, request features, and share feedback.
- Follow us on X/Twitter for updates and announcements.
/ecosystem-ci run
📝 Ran ecosystem CI: Open
| suite | result | latest scheduled |
|---|---|---|
| language-tools | :white_check_mark: success | :white_check_mark: success |
| pinia | :white_check_mark: success | :white_check_mark: success |
| radix-vue | :white_check_mark: success | :white_check_mark: success |
| primevue | :white_check_mark: success | :white_check_mark: success |
| vite-plugin-vue | :white_check_mark: success | :white_check_mark: success |
| nuxt | :white_check_mark: success | :white_check_mark: success |
| test-utils | :white_check_mark: success | :white_check_mark: success |
| quasar | :white_check_mark: success | :white_check_mark: success |
| vitepress | :white_check_mark: success | :white_check_mark: success |
| vuetify | :white_check_mark: success | :white_check_mark: success |
| vue-simple-compiler | :white_check_mark: success | :white_check_mark: success |
| vue-macros | :white_check_mark: success | :white_check_mark: success |
| vant | :white_check_mark: success | :white_check_mark: success |
| vueuse | :white_check_mark: success | :white_check_mark: success |
| vue-i18n | :white_check_mark: success | :white_check_mark: success |
| router | :white_check_mark: success | :white_check_mark: success |