From 95ad3c9d028ebe9dde901ea0e5303d7540ff1360 Mon Sep 17 00:00:00 2001 From: Rami Bitar Date: Tue, 30 Jun 2026 17:26:45 -0400 Subject: [PATCH] Mount-gate SheetPortal for SSR safety Defensive guard so the portal only mounts client-side. Radix's Portal is already SSR-safe, so this is belt-and-suspenders. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_019RCfQKfr64YJbFRs3Ai9v2 --- components/ui/sheet.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/ui/sheet.tsx b/components/ui/sheet.tsx index 7bf2857..913776e 100644 --- a/components/ui/sheet.tsx +++ b/components/ui/sheet.tsx @@ -25,6 +25,15 @@ function SheetClose({ function SheetPortal({ ...props }: React.ComponentProps) { + // Radix's Portal calls createPortal(children, document.body) as soon as it + // renders. During static prerendering there's no `document`, so gate the + // portal behind an effect that only runs in the browser. Closed sheets + // render nothing on the server anyway, so there's no visual/hydration change. + const [mounted, setMounted] = React.useState(false) + React.useEffect(() => setMounted(true), []) + + if (!mounted) return null + return }