Next.js Discord

Discord Forum

How to make page properties available to the RootLayout

Unanswered
Sokoke posted this in #help-forum
Open in Discord
SokokeOP
I have tried various things like Metadata, trying to use a page context (which feels overly complicated), ...

I have my root layout currently defined as:
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const subTitle = ''; //<-- how to get property from here?
  return (
    <html lang="en">
      <body>
        <div style={layoutStyle}>
          <PageHeader subTitle={subTitle} />
          <main>{children}</main>
          <PageFooter />
        </div>
      </body>
    </html>
  );
}


From my page.tsx, how can I make this subTitle property available to the RootLayout?

For instance, metadata doesn't work because it is not being injected into the RootLayout (even when I add a parameters) :
export const metadata: Metadata = {
  other: {
    subTitle: 'My subtitle',
  },
};


I am using the latest next.js 15.2.2 with typescript, AppRouter (essentially all Yes when initializing from create-next-app@latest).

It feels like there should be a way to achieve this with little friction.
Any ideas?

5 Replies

You want your Layout and page to share the same data?

Metadata can only have access to whatever route you’re currently on.
Not sure I fully understand the issue. But this might not be possible since pages and layouts are rendered and [evaluated independently](https://nextjs-faq.com/client-components-wrapping-server-component-children#some-more-advanced-notes), not at the same time, neither are guaranteed to run in order.
SokokeOP
I don't necessarily want Metadata .

I was looking for a simple way on my page.tsx to define a property, specifically a subTitle for the page. Then in my RootLayout it could access that variable.

In the RootLayout, I have defined my PageHeader, which takes a subTitle:
<PageHeader subTitle={subTitle} />

I would like that to be different depending on which page they are on. But I don't want to have to redefine the header component on each page.

Another thing I tried was adding a subTitle as an argument to my RootLayout, then trying to set the layout on my page:
MyPage.getLayout = (page: React.ReactNode) => (
  <RootLayout subTitle="My subtitle">{page}</RootLayout>
);

Then:
export default function RootLayout({
  children,
  subTitle = '',       // <-- can this be passed from child?
}: Readonly<{
  children: React.ReactNode;
  subTitle?: string;
}>) {
  return (
    <html lang="en">
      <body>
        <div style={layoutStyle}>
          <PageHeader subTitle={subTitle} />
          <main>{children}</main>
          <PageFooter />
        </div>
      </body>
    </html>
  );
}

I don't think that is available for the version of next.js/AppRouter that I am using. I also see this error on build:
src/app/layout.tsx
Type error: Layout "src/app/layout.tsx" has an invalid "default" export:
  Type "Readonly<{ children: ReactNode; subTitle?: string | undefined; }>" is not valid.


Is there another way to achieve this? Other than say having to break out that part into another component. I was trying to avoid that and keep it simple.
Let’s clarify some things first. It’s not possible to pass data from layout to page and viceversa. You just can’t because these components are evaluated independently from each other. They end up rendering nested in the same tree once they reach the browser but in the server there’s no way to share data between these. So, short answer: no, it’s not possible the way you want to do it.

Also, you can’t pass props to Layouts since layouts don’t re-render and are mostly static shells of you app. They receive params through props, and you can do something like this [(from the docs)](https://nextjs.org/docs/app/api-reference/file-conventions/layout#displaying-content-based-on-params):
export default async function DashboardLayout({
  children,
  params,
}: {
  children: React.ReactNode
  params: Promise<{ team: string }>
}) {
  const { team } = await params
 
  return (
    <section>
      <header>
        <h1>Welcome to {team}'s Dashboard</h1>
      </header>
      <main>{children}</main>
    </section>
  )
}


Another approach would be to make <PageHeader> a client component and make it re-render on page navigation, you could do this by having your <PageHeader> component read params or searchParams with the hooks provided by Next.js (useParams() and useSearchParams()) but make sure you wrap that <HeaderComponent> in <Suspense> when you render it inside of the Layout
@Sokoke any updates?