VOOZH about

URL: https://alexop.dev/posts/how-vueuse-solves-ssr-window-errors-vue-applications/

⇱ How VueUse Solves SSR Window Errors in Vue Applications | alexop.dev


Next Talk: Automating Web Development with Claude Code

July 1, 2026 — DWX Developer World, Mannheim

Conference

How VueUse Solves SSR Window Errors in Vue Applications

Published: at 

I am a big fan of VueUse. Every time I browse the docs I discover a new utility that saves me hours of work. Yet VueUse does more than offer nice functions. It also keeps your code safe when you mix client-side JavaScript with server-side rendering (SSR). In this post I show the typical window is not defined” problem, explain why it happens, and walk through the simple tricks VueUse uses to avoid it.

The Usual Pain: window Fails on the Server#

When you run a Vue app with SSR, Vue executes in two places:

  1. Server (Node.js) – It renders HTML so the user sees a fast first screen.
  2. Browser (JavaScript runtime in the user’s tab) – It takes over and adds interactivity.

The server uses Node.js, which has no browser objects like window, document, or navigator. The browser has them. If code that needs window runs on the server, Node.js throws an error and the page render breaks.

Diagram: How SSR Works#

Node.js vs Browser: Two Different Worlds#

FeatureNode.js on the serverBrowser in the tab
window❌ not defined✅ defined
document
navigator
DOM access
GoalRender HTML fastAdd interactivity

A Vue composable that reads the mouse position or listens to scroll events needs those browser objects. It must not run while the server renders.

How VueUse Solves the Problem#

VueUse uses three small patterns: a client check, safe defaults, and an SSR guard inside each composable.

1. One-Line Client Check#

VueUse first asks, “Are we in the browser?” It does that in is.ts:

export const isClient =
 typeof window !== "undefined" && typeof document !== "undefined";

Diagram#

2. Safe Defaults for Browser Objects#

Instead of making you write if (isClient) checks, VueUse exports harmless fallbacks from _configurable.ts:

import { isClient } from "@vueuse/shared";

export const defaultWindow = isClient ? window : undefined;
export const defaultDocument = isClient ? window.document : undefined;
export const defaultNavigator = isClient ? window.navigator : undefined;

On the server these constants are undefined. That value is safe to read, so nothing crashes.

Diagram#

3. The SSR Guard Inside Every Composable#

Each composable that might touch the DOM adds a simple guard. Example: onElementRemoval:

export function onElementRemoval(options: any = {}) {
 const { window = defaultWindow } = options;

 if (!window)
 // server path
 return () => {}; // no-op

 // browser logic goes here
}

If window is undefined, the function returns a no-op and exits. The server render keeps going without errors.

Diagram#

4. Extra Safety with useSupported#

Sometimes you are in the browser, but the user’s browser lacks a feature. VueUse offers useSupported to check that:

export function useSupported(test: () => unknown) {
 const isMounted = useMounted();
 return computed(() => {
 isMounted.value; // make it reactive
 return Boolean(test());
 });
}

Example: useEyeDropper#

useEyeDropper checks both SSR and feature support (see the full file here):

export function useEyeDropper() {
 const isSupported = useSupported(
 () => typeof window !== "undefined" && "EyeDropper" in window
 );

 async function open() {
 if (!isSupported.value) return; // safe exit
 const eyeDropper = new (window as any).EyeDropper();
 await eyeDropper.open();
 }

 return { isSupported, open };
}

Wrap-Up#

  • Node.js renders HTML but lacks browser globals.
  • VueUse avoids crashes with three steps:
    1. A single isClient flag tells where the code runs.
    2. Safe defaults turn window, document, and navigator into undefined on the server.
    3. Every composable adds a quick SSR guard that eliminates environment concerns.

Because of this design you can import any VueUse composable, even ones that touch the DOM, and trust it to work in SSR without extra code.

Learn More#

Stay Updated!

Subscribe to my newsletter for more TypeScript, Vue, and web dev insights directly in your inbox.

  • Background information about the articles
  • Weekly Summary of all the interesting blog posts that I read
  • Small tips and trick
Subscribe Now
Share this post on:
Share this post via WhatsAppShare this post on FacebookTweet this postShare this post via TelegramShare this post on PinterestShare this post via emailShare this post on LinkedIn