Skip to content

Commit 8d9e85d

Browse files
committed
fix(web): eliminate Clerk UserButton hydration mismatch in app header
Clerk's <UserButton> mounts a client-only div not present in SSR HTML, throwing a hydration mismatch on every (app) page and forcing a client tree regeneration. Gated it behind <ClerkLoaded>/<ClerkLoading> (idiomatic) so SSR + first client render match. Verified: 0 hydration errors after reload (was recurring).
1 parent 5b4a12a commit 8d9e85d

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

apps/web/src/components/shell/thread-header.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { UserButton, useAuth } from "@clerk/nextjs";
3+
import { ClerkLoaded, ClerkLoading, UserButton, useAuth } from "@clerk/nextjs";
44
import { useQuery } from "@tanstack/react-query";
55
import Image from "next/image";
66
import { usePathname, useSearchParams } from "next/navigation";
@@ -61,7 +61,14 @@ export function ThreadHeader() {
6161
<Zap aria-hidden="true" className="h-3.5 w-3.5" />
6262
Integrations
6363
</a>
64-
<UserButton />
64+
{/* Gate Clerk's UserButton behind ClerkLoaded so SSR and the first client render
65+
match (it mounts a client-only div); avoids a hydration-mismatch tree regen. */}
66+
<ClerkLoading>
67+
<div aria-hidden="true" className="h-7 w-7 rounded-full bg-thread-skeleton" />
68+
</ClerkLoading>
69+
<ClerkLoaded>
70+
<UserButton />
71+
</ClerkLoaded>
6572
</div>
6673
</header>
6774
);

0 commit comments

Comments
 (0)