DEV Community

Cover image for Creating Varied Layouts for Different NextJS Pages
Radzion Chachura
Radzion Chachura

Posted on • Originally published at radzion.com

Creating Varied Layouts for Different NextJS Pages

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.

Sidebar

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

_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
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
michaeltharrington profile image
Michael Tharrington

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! 🙂

Collapse
 
radzion profile image
Radzion Chachura

Thanks! Will try that :)