✨ Watch on YouTube | 🐙 GitHub | 🎮 Demo
In this post, we will learn how to create different layouts for different NextJS pages. We'll examine how this is done at increaser.org, which incorporates four layout variations. Although Increaser's repository is private, you can find all the code in the ReactKit repository as it also uses different layouts for the landing page and the remaining pages.
Why not use layout components directly in the page component?
We could use different layout components directly in the page component. However, the issue arises when we navigate between pages with the same layout. The layout ends up being re-rendered. This becomes problematic when you have a sidebar layout with a scroll, and, as you scroll down and move to another page, the scroll resets. Thus, we need a method that allows different layouts for different pages, while also maintaining the layout when we navigate between pages with the same layout for improved user experience.
How to create different layouts for different pages?
At Increaser, we implement four different layouts:
- Authorization pages that have the same top bar as the landing page.
- App pages with the sidebar.
- Project pages that also contain additional navigation between projects.
- A full-screen focus page that lacks any navigation.
To accomplish this, we use three helper functions: makeAppPage
, makeAuthPage
, and makeProjectsPage
.
import { Page, GetLayout } from "layout/Page"
import { AppPageLayout } from "focus/components/AppPageLayout"
const getAppPageLayout: GetLayout = (page) => (
<AppPageLayout>{page}</AppPageLayout>
)
export const makeAppPage = (page: Page) => {
page.getLayout = getAppPageLayout
return page
}
All of these functions look alike. Each is a function that takes a component and adds a getLayout
function to it, which wraps the page within a specific layout.
import { NextPage } from "next"
import { ReactNode } from "react"
export type GetLayout = (page: ReactNode) => ReactNode
export type Page<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: GetLayout
}
The Page
type is simply a NextJS page with an extra function. The GetLayout
type describes a function that takes one React node and returns another React node.
How to use page layout helpers?
Here is how we use our helpers: we wrap the page component with the helper function, as exemplified in this sign-up page.
import { SignUpContent } from "auth/components/SignUpContent"
import { makeAuthPage } from "layout/makeAuthPage"
export default makeAuthPage(SignUpContent)
Without the helper, we would have more code to write:
import { SignUpContent } from "auth/components/SignUpContent"
import { AppPageLayout } from "focus/components/AppPageLayout"
import { Page } from "layout/Page"
const SignUpPage: Page = SignUpContent
export default SignUpPage
SignUpPage.getLayout = (page) => <AppPageLayout>{page}</AppPageLayout>
_app.tsx and getLayout
In which context do we call the getLayout
function?
function MyApp({ Component, pageProps }: MyAppProps) {
const getLayout = Component.getLayout || ((page: ReactNode) => page)
const component = getLayout(<Component {...pageProps} />)
return (
<ThemeProvider>
<GlobalStyle fontFamily={inter.style.fontFamily} />
{component}
</ThemeProvider>
)
}
export default MyApp
It will be the _app.tsx
file that calls the getLayout
function. If the page lacks a getLayout
function like the focus page at Increaser, it will simply return the page component.
Top comments (2)
Heyo Rodion!
Awesome post here. 🙌
In case you didn't already know, DEV actually allows folks to embed YouTube & Vimeo videos using the following syntax:
{% embed https://... %}
You don't have to embed your video, but just wanted to make you aware in case you wanna.
By the way, here's a link to the editor guide where you can see our other available embeds and various MD formatting options.
Hope this is helpful! 🙂
Thanks! Will try that :)