How to make page properties available to the RootLayout
Unanswered
Sokoke posted this in #help-forum
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:
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) :
I am using the latest next.js
It feels like there should be a way to achieve this with little friction.
Any ideas?
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.
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
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:
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:
Then:
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:
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.
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
Another approach would be to make
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?