#8227·swiper

Vue: default slot is invoked outside the render function in JSX, logging a warning on every Swiper

Author: jarofbillyCreated Sep 2, 2026Updated Sep 2, 2026
Labelst0ggles

Check that this is really a bug

  • I confirm

Reproduction link

https://codesandbox.io/s/github/jarofbilly/swiper-vue-jsx-slot-warning

Source: https://github.com/jarofbilly/swiper-vue-jsx-slot-warning Also runs on StackBlitz: https://stackblitz.com/github/jarofbilly/swiper-vue-jsx-slot-warning

Bug description

Every <Swiper> in a Vue JSX/TSX project logs this on mount:

[Vue warn]: Slot "default" invoked outside of the render function: this will not track
dependencies used in the slot. Invoke the slot function inside the render function instead.

This was reported in #4974 (Swiper 7.0.6) and closed with "it is actually fine as everything works correctly, just ignore this warning". That assessment still holds and I am not disputing it. I tested reactive state read only inside the slot and it updates correctly with or without a workaround, so nothing is broken. I am opening a fresh issue rather than commenting on a closed one because the ask is different: the warning is still present four years later in 14.2.0, it is unavoidable noise for every Vue JSX consumer, and I am offering to fix it.

getChildren() in swiper-vue.mjs calls slots.default(). It runs from three places:

Line (14.2.0) Context Warns
393 directly in setup() yes
397 onBeforeBreakpoint yes
489 inside the returned render function no

Line 489 is fine. The other two run outside a render pass, so currentRenderingInstance is null and Vue warns.

Why this only affects JSX

The two compilers wrap slots differently. Same component, same slot:

javascript
// @vue/compiler-sfc
default: _withCtx(() => [ ... ])

// @vue/babel-plugin-jsx (both array-children and object-slot forms)
default: () => [ ... ]

_withCtx sets the rendering instance for the duration of the call, so SFC users never see the warning even though the same setup-time call happens for them too. That is why this looks rare despite affecting every JSX consumer.

Possible fix

slidesRef is consumed at lines 415, 418 and 434, all of which run at or after mount. Vue's order is setup() then render() then mounted(), and the render function already calls getChildren() at line 489, so slidesRef is populated before anything reads it. On that reading the setup() call looks redundant. onBeforeBreakpoint sets breakpointChanged.value, which triggers a re-render and therefore another getChildren(), so it may be redundant too.

Two things would need verifying before that could ship, which is what a PR and your test suite would settle:

  1. whether oldSlidesRef starting empty rather than pre-seeded changes first-update behaviour through getChangedParams
  2. whether breakpoint changes still pick up slide changes in the right order

Happy to be told a different approach is preferred.

Expected Behavior

No warning, since nothing is actually wrong.

Actual Behavior

Every <Swiper> instance logs the warning on mount. In an app with several carousels the console fills with it on every page load.

Swiper version

14.2.0. Also reproduces on 14.1.0 (same code at lines 393/397/489) and originally reported in #4974 against 7.0.6.

Platform/Target and Browser Versions

Windows 11, Firefox 154. Compiler level rather than browser specific.

Reproduction environment: vue 3.5.42, @vue/babel-plugin-jsx 1.5.0 via @vitejs/plugin-vue-jsx 4.2.0, vite 6.4.3. Originally hit on @vue/babel-plugin-jsx 2.0.1 via @vitejs/plugin-vue-jsx 5.1.x, so it is not specific to one major of the JSX plugin.

Validations

  • Follow our Code of Conduct
  • Read the docs.
  • Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
  • Make sure this is a Swiper issue and not a framework-specific issue

Would you like to open a PR for this bug?

  • I'm willing to open a PR