shadcn-ui/ui

[bug]: Initially opened dialog causes hydration error

isRyven opened this issue · 1 comments

Describe the bug

Using a Dialog component, which is initially opened, throws a hydration exception.

image

image

image

Affected component/components

Dialog

How to reproduce

1. Initiate latest next project:

npx create-next-app@latest dialog-bug-shadcn --typescript --tailwind --eslint
cd  dialog-bug-shadcn

2. Initiate shadcn:

npx shadcn-ui@latest init

3. Add Dialog component:

npx shadcn-ui@latest add dialog

4. Use the Dialog component with open property set to true:

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";

export default function Home() {
  return (
    <div className="p-4">
      <Dialog open={true} modal={false}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Are you absolutely sure?</DialogTitle>
            <DialogDescription>
              This action cannot be undone. This will permanently delete your
              account and remove your data from our servers.
            </DialogDescription>
          </DialogHeader>
        </DialogContent>
      </Dialog>
    </div>
  );
}

5. Run the next dev server:

npm run dev

Codesandbox/StackBlitz link

https://stackblitz.com/edit/stackblitz-starters-c11bus

Logs

Unhandled Runtime Error

Error: Hydration failed because the initial UI does not match what was rendered on the server.
See more info here: https://nextjs.org/docs/messages/react-hydration-error

Expected server HTML to contain a matching <div> in <div>.

<Home>
  <div>
  ^^^^^
    <$5d3850c4d0b4e6c7$export$3ddf2d174ce01153>
      <Provider>
        <_c1>
          <$5d3850c4d0b4e6c7$export$dad7c95542bacce0>
            <Provider>
              <$921a889cee6df7e8$export$99c2b779aa4e8b8b>
                <eval>
                  <eval>
                    <eval>
                      <eval>
                        <eval>
                          <$921a889cee6df7e8$export$99c2b779aa4e8b8b>
                            <eval>
                              <eval>
                                <eval>
                                  <eval>
                                    <eval>
                                      <eval>
                                        <eval>
                                          <eval>
                                            <div>

Callstack

throwOnHydrationMismatch
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (6981:1)
tryToClaimNextHydratableInstance
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (7016:1)
updateHostComponent$1
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (16621:1)
beginWork$1
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (18503:1)
HTMLUnknownElement.callCallback
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (20565:1)
Object.invokeGuardedCallbackImpl
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (20614:1)
invokeGuardedCallback
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (20689:1)
beginWork
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (26949:1)
performUnitOfWork
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (25748:1)
workLoopConcurrent
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (25734:1)
renderRootConcurrent
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (25690:1)
performConcurrentWorkOnRoot
node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js (24504:1)
workLoop
node_modules/next/dist/compiled/scheduler/cjs/scheduler.development.js (256:1)
flushWork
node_modules/next/dist/compiled/scheduler/cjs/scheduler.development.js (225:1)
MessagePort.performWorkUntilDeadline
node_modules/next/dist/compiled/scheduler/cjs/scheduler.development.js (534:1)

System Info

Sytem:

OS: macOS 14.4.1 23E224 arm64
Host: MacBookPro18,3
Kernel: 23.4.0
CPU: Apple M1 Pro
GPU: Apple M1 Pro

Browser:

Arc
Version 1.40.0 (49176)
Chromium Engine Version 124.0.6367.79

Before submitting

  • I've made research efforts and searched the documentation
  • I've searched for existing issues

Hi @isRyven

According to the official Next.js documentation on hydration errors, a hydration error occurs when:

While rendering your application, there was a difference between the React tree that was pre-rendered from the server and the React tree that was rendered during the first render in the browser.

Since the dialog initially requires JavaScript to render, a discrepancy can arise. After the server renders the HTML, the client-side JavaScript executes and potentially introduces new HTML content, which may not match the HTML that was rendered by the server.

To solve this, you have two options:

  • Import the Dialog component dynamically on the client side and disable SSR (Server-Side Rendering) for it:
    const Dialog = dynamic(() => import('@/components/ui/dialog').then((mod) => mod.Dialog), { ssr: false });
  • Delay rendering until after the server has finished generating the HTML. This can be managed by checking a state that is set only on the client:
const [isClient, setIsClient] = useState(false);
useEffect(() => {
  setIsClient(true);
}, [])

When isClient is true, it indicates that the client has taken over rendering from the server.

Cheers!