Next.js Discord

Discord Forum

Why is my error.tsx rendering without layout and outside of the <body>??

Answered
dperolio posted this in #help-forum
Open in Discord
Avatar
My error.tsx:

'use client'
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </>
  )
}
Image
Answered by not-milo.tsx
That's unusual. Ideally you shouldn't need to make a wrapper for the body just to pass props down to your header/footer components.
View full answer

36 Replies

Avatar
@English Angora made a new post as it seems a different question.
Avatar
English Angora
Can you send your root layout file please
Avatar
import { Providers } from '#components';

export { viewport, metadata } from './[locale]/layout';

import '../styles/global.scss';

export default async function RootLayout ({ children }: { children: React.ReactNode }) {
  return (
    <Providers user={null} lang={'en'}>
      <html lang='en' dir='ltr'>
        {children}
      </html>
    </Providers>
  );
}
Avatar
@not-milo.tsx
Avatar
How does your file structure look like?
Avatar
/app
[locale]
- page.tsx
- layout.tsx
- error.tsx
- layout.tsx
- not-found.tsx
- global-error.tsx
Avatar
I suspect you have your error.tsx file somewhere where it's not being wrapped by the body. Usually you should declare your html and body elements together in the same place.
Where's the body being rendered?
Avatar
Yeah, that's what I wanted to do, in layout.tsx, but I need to pass props to the header and footer from the page, so I created a <Body> component and use that as my page wrapper.
Oh, good point. Maybe the lack of a body is screwing it up.
Although, I think I had one, and it was rendering 2 <body>'s.
Let me see.
Avatar
That's unusual. Ideally you shouldn't need to make a wrapper for the body just to pass props down to your header/footer components.
Answer
Avatar
How would you do it?
Avatar
Also, from this it's not that clear how it's structured. It seems like you have two layout files at the same level and a directory is missing :spinning_think:
It depends on what you need to pass down. All I can do rn is some educated guesses.
Avatar
Whatever I want to. Various props to show/hide the header/footer, logo, change links, etc.
Avatar
Nope, adding <Body> to error.tsx didn't help.
It wrapped it in a... div.
Still outside the html.
Avatar
Since those two components are direct children of the body element you don't have to separate that part into a different file. You can just have everything nested as usual:
export default async function RootLayout({props}: LayoutProps) {
  return (
  <html lang={props.params.lang}>
    <body>
      <TopNav lang={props.params.lang} />
      {children}
      <Footer lang={props.params.lang} />
    </body>
  </html>
  );
}
Avatar
Body
export default function Body ({ className, showBackground, header = {}, footer = {}, children }: BodyProps) {
  return (
    <body className={classNames(className,
      'bg-no-repeat bg-center bg-cover bg-fixed min-h-screen text-white', {
        'bg-body-gradient-image bg-blend-multiply overflow-x-hidden': showBackground,
        'bg-body-gradient': !showBackground
      })}>
      <div className='max-w-screen-lg mx-auto mb-16 w-full p-4'>
        {!header.hide && <Header {...header} />}
        <main className='content'>
          {children}
        </main>
      </div>
      {!footer.hide && <Footer {...footer} />}
    </body>
  );
}
lang isn't what I need to pass to the header and footer.
I want to pass arbitrary non-param props, from the page.tsx. And my setup works for that. But it looks like the <Body> is the issue. Apparently Next requires the body to be in the layout, because adding it to the layout fixes error.tsx.
Avatar
Yeah, when an error is thrown the rendering of elements nested in lower levels gets messed up. So in this case your Body component doesn't get rendered properly and you end up having your error contnts outside of it.
Btw, are those props coming from the context?
Avatar
Nope, I was just passing in normal props. e.g., <Body showBackground footer={{ hide: true }}>
Oh, I was wrong.
Even adding the body to layout, it's still rendering the content outside of the html. :/
Avatar
:thonk_explode:
Can you share the repo?
Avatar
Image
Weird.
Avatar
It's expected, the same way as you can't render a button inside another button.
Btw, it's getting really late where I live. So if by tomorrow morning you haven't solved it yet we can continue debugging ✌🏻
Avatar
Okay, good night, and thanks, I think you've given me enough to solve it now.