Skip to content

Commit 7a4a8df

Browse files
committed
fix: resolve SSR hydration errors in copy-to-clipboard demo
- Add proper typeof checks for window, navigator, and document - Use useEffect for client-side copy support detection - Add loading state while checking browser capabilities - Prevent 'window is not defined' errors during server-side rendering
1 parent a701e47 commit 7a4a8df

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

app/demo/copy-to-clipboard/page.tsx

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

3-
import { useState } from "react";
3+
import { useState, useEffect } from "react";
44
import { Button } from "@/components/ui/button";
55
import {
66
CopyButton,
@@ -31,6 +31,7 @@ import { Check, Copy, Download, FileText, Globe, Code } from "lucide-react";
3131
export default function CopyToClipboardDemo() {
3232
const [customText, setCustomText] = useState("Hello, World!");
3333
const [copyResult, setCopyResult] = useState<string>("");
34+
const [isSupported, setIsSupported] = useState<boolean | null>(null);
3435
const [testFiles] = useState([
3536
{ name: "index.js", content: 'console.log("Hello, World!");' },
3637
{
@@ -40,6 +41,11 @@ export default function CopyToClipboardDemo() {
4041
{ name: "README.md", content: "# My Project\n\nThis is a sample project." },
4142
]);
4243

44+
// Check copy support on client side only
45+
useEffect(() => {
46+
setIsSupported(isCopySupported());
47+
}, []);
48+
4349
const handleCustomCopy = async () => {
4450
const result = await copyToClipboard(customText);
4551
setCopyResult(
@@ -101,7 +107,9 @@ export default function CopyToClipboardDemo() {
101107
</p>
102108
<div className="mt-4 flex items-center gap-2">
103109
<span className="text-sm">Copy Support:</span>
104-
{isCopySupported() ? (
110+
{isSupported === null ? (
111+
<span className="text-muted-foreground">Checking...</span>
112+
) : isSupported ? (
105113
<span className="inline-flex items-center gap-1 text-green-600">
106114
<Check className="h-4 w-4" />
107115
Supported
@@ -408,17 +416,30 @@ export default function CopyToClipboardDemo() {
408416
<ul className="text-muted-foreground space-y-1 text-sm">
409417
<li>
410418
• Modern Clipboard API:{" "}
411-
{navigator.clipboard ? "✅" : "❌"}
419+
{typeof navigator !== "undefined" && navigator.clipboard
420+
? "✅"
421+
: "❌"}
412422
</li>
413423
<li>
414-
• Secure Context: {window.isSecureContext ? "✅" : "❌"}
424+
• Secure Context:{" "}
425+
{typeof window !== "undefined" && window.isSecureContext
426+
? "✅"
427+
: "❌"}
415428
</li>
416429
<li>
417430
• Fallback Support:{" "}
418-
{document.queryCommandSupported?.("copy") ? "✅" : "❌"}
431+
{typeof document !== "undefined" &&
432+
document.queryCommandSupported?.("copy")
433+
? "✅"
434+
: "❌"}
419435
</li>
420436
<li>
421-
• Overall Support: {isCopySupported() ? "✅" : "❌"}
437+
• Overall Support:{" "}
438+
{isSupported === null
439+
? "⏳"
440+
: isSupported
441+
? "✅"
442+
: "❌"}
422443
</li>
423444
</ul>
424445
</div>

0 commit comments

Comments
 (0)