Description
The login page at src/app/login/page.tsx has a React hydration mismatch. The server renders the loading spinner (.auth-loading) while the client hydrates to the actual login form (.auth-brand), causing a full-page re-render on every visit.
Root Cause
The LoginPageContent component (line 77-85) checks isLoading from useAuth() before rendering. On the server, isLoading defaults to true (no auth context available), so it renders the loading state. On the client, isLoading quickly resolves to false, and React tries to hydrate a completely different DOM tree — triggering the mismatch.
Server output: <div class="auth-loading"><div class="auth-spinner"></div></div>
Client output: <div class="auth-brand">...<div class="auth-brand-content">...</div></div>
Impact
- Causes Next.js hydration warning/error on every page load
- Login page may flash loading state before rendering
- Breaks E2E tests that rely on the login page rendering reliably
Fix Approach
Replace the server-side loading check with a client-side only guard using a useSyncExternalStore approach, or restructure so the server renders the same initial tree as the client.
Description
The login page at
src/app/login/page.tsxhas a React hydration mismatch. The server renders the loading spinner (.auth-loading) while the client hydrates to the actual login form (.auth-brand), causing a full-page re-render on every visit.Root Cause
The
LoginPageContentcomponent (line 77-85) checksisLoadingfromuseAuth()before rendering. On the server,isLoadingdefaults totrue(no auth context available), so it renders the loading state. On the client,isLoadingquickly resolves tofalse, and React tries to hydrate a completely different DOM tree — triggering the mismatch.Server output:
<div class="auth-loading"><div class="auth-spinner"></div></div>Client output:
<div class="auth-brand">...<div class="auth-brand-content">...</div></div>Impact
Fix Approach
Replace the server-side loading check with a client-side only guard using a
useSyncExternalStoreapproach, or restructure so the server renders the same initial tree as the client.