Smell Hydration Unsafe Init
Anti-pattern where a component's initial render reads browser-only APIs (localStorage/sessionStorage/window/document/matchMedia) or render-time values (Date.now, new Date, Math.random, unzoned toLocale*) so server and client first-render disagree, breaking hydration.
Tags
Impact
A SvelteKit component whose initial render depends on browser-only or render-time state produces different HTML on the server than on the client's first (hydration) render. Svelte detects the divergence (hydration_mismatch), tears down the affected subtree, and rebuilds it client-side. During that window event handlers are not yet live, so the user's first interactions (clicks on a sidebar disclosure, a toggle, a menu) are silently DROPPED — then "work after a few seconds." It also spams the console with hydration_mismatch, masking real errors, and can flash stale/incorrect content.
Symptoms
- A component reads localStorage/sessionStorage/window/document/matchMedia during initial render (commonly behind `if (typeof window !== 'undefined')` at script top or in a $state initializer) to restore persisted UI state.
- Markup renders an unzoned `toLocaleString`/`toLocaleDateString` or a relative time derived from `Date.now()` on an SSR'd page, so server (UTC) and client (viewer TZ / later clock) produce different text.
- Interactive elements (sidebar disclosure, toggles, menus) ignore the first click(s) after load and only respond "after a few seconds"; the console shows svelte.dev/e/hydration_mismatch.
Source
Svelte 5 official documentation — svelte.dev/docs — hydration; svelte.dev/e/hydration_mismatch(2026)