Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug Report][4.0.4] SSR crash in useFocusTrap: onScopeDispose accesses document without IN_BROWSER guard #22762

Description

@BatLeDev

Environment

Vuetify Version: 4.0.4
Vue Version: 3.5.31+
OS: Any (server-side rendering context)

Steps to reproduce

  1. Use Nuxt (or any SSR framework) with Vuetify 4.0.4 and Vue 3.5.31+
  2. Render any component using useFocusTrap (e.g. VDialog, VMenu with retainFocus, VSelect)
  3. Request the page server-side

Expected Behavior

SSR rendering completes without errors.

Actual Behavior

SSR crashes with:

Error: Cannot read properties of undefined (reading 'removeEventListener')
  at Array.<anonymous> (node_modules/vuetify/lib/composables/focusTrap.js:129:14)
  at EffectScope.stop (@vue/reactivity/dist/reactivity.cjs.js:124:25)
  at cleanupContext (@vue/server-renderer/dist/server-renderer.cjs.js:662:15)
  at renderToString (@vue/server-renderer/dist/server-renderer.cjs.js:1014:5)

Root cause

Vue 3.5.31 fixed a bug where EffectScope.stop() was not executing onScopeDispose callbacks during SSR (vue-core#14548). With the fix, Vue now correctly calls those callbacks on the server — but Vuetify's onScopeDispose in composables/focusTrap.js calls document.removeEventListener directly without an IN_BROWSER guard:

if (IN_BROWSER) {
  // ✅ setup listeners correctly guarded
}

onScopeDispose(() => {
  registry.delete(trapId);
  clearTimeout(focusTrapSuppressionTimeout);
  document.removeEventListener('pointerdown', onPointerdown);   // ❌ not guarded
  document.removeEventListener('focusin', captureOnFocus);
  document.removeEventListener('keydown', captureOnKeydown);
  if (--subscribers < 1) {
    document.removeEventListener('keydown', onKeydown);
  }
});

On the server, document is undefined, causing the crash.

Workaround: pin Vue to 3.5.30 until a fix is released.

Expected fix: wrap the document.removeEventListener calls inside onScopeDispose with the same IN_BROWSER check used in the setup block.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions