DEV Community 👩‍💻👨‍💻

Cover image for Guide to Layouts and Page Specific Layouts in NextJS
professorjrod
professorjrod

Posted on

Guide to Layouts and Page Specific Layouts in NextJS

Layouts are a powerful abstract concept in NextJS.

It is a declarative way of telling Next the general layout of your pages without reusing code. Most commonly, this is just a navbar and a footer.

However, some use cases require pages to have their own layouts, rather than one for every single page. Some even require nested layouts!

Personally, I found it rather confusing trying to figure out how layouts work when I was getting started. Let me break it down for you.

If you haven't used layouts in NextJS, this is how they work.

import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

This is your standard Layout component. Here we are passing a React component as props, and rendering it in between a Navbar and a Footer.

Children is going to be the page components that are being passed as props. This will come from your main app component.

In order to use this, we can import it in app and pass our page components as props like so:

import Layout from '../components/layout'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}
Enter fullscreen mode Exit fullscreen mode

For those new to React, this is an example of a higher order component

Now that you have imported and used the Layout component, all of your pages from app are going to be formatted as you did in the layout definition. In this case, they will all have a <Navbar> above and a <Footer> below.

But what if you need a different layout? What if some pages need to have a sidebar as well as the <Navbar> and <Footer>?

This is called a page specific layout. There are a lot of different ways to implement this, and some have their own advantages and disadvantages. But I think the simplest and most effective way is by creating a new property for our page components.

First, make the layout. You can do so just like the first example. Import the component that you want to incorporate in the layout, then declare children as props.

import React from "react";
import Sidebar from "../comps/sidebar";

export const SidebarLayout = ({ children }) => {
  return (
    <div>
      <Sidebar />
      {children}
    </div>
  );
};

export default SidebarLayout;
Enter fullscreen mode Exit fullscreen mode

Above, we declared that the <Sidebar> is going to live above the components. Now in order to actually render this to the screen, it's going to be a little different.

First, in the component that needs a specific layout, import the layout.

Then you need to give it a new property. I like to use PageLayout. I do this at the bottom of the component before my exports.

import React from "react";
import SnapshotLayout from "../layouts/snapshot";

const MyNotes = (props: any) => {
  return (
    <div>
      <textarea placeholder="Write notes here!"></textarea>
    </div>
  );
};

MyNotes.PageLayout = SnapshotLayout;

export default MyNotes;
Enter fullscreen mode Exit fullscreen mode

By adding MyNotes.PageLayout = SnapshotLayout;, we have given our new JSX element the property PageLayout. It's value is the layout we just made. This isn't going to render correctly though - Next doesn't know what to do with this information yet.

Now in order to render the correct layout for each page, let's add logic for it in App.

import React from "react";
import Layout from "../components/layout";
import "../styles/globals.css";

const MyApp = ({ Component, pageProps } ) => {
  return (
    <Layout>
      {Component.PageLayout ? (
        <Component.PageLayout>
          <Component {...pageProps} />
        </Component.PageLayout>
      ) : (
        <Component {...pageProps} />
      )}
    </Layout>
  );
};

export default MyApp;
Enter fullscreen mode Exit fullscreen mode

Here, we have done two things. First we make a ternary statement. We check if the property PageLayout exists on a component. If so, render it with the PageLayout as a higher order component.

If not, simply render it without the page specific layout.

This works because we defined the property PageLayout in our component. When App retrieves a component, it's properties become accessible. The layout becomes it's own component because we extract it and declare it as a component. <Component.PageLayout> in this example would be the same as writing <SidebarLayout>.

The advantage of rendering layouts this way is scalability. Say you want to make more layouts for pages. All you have to do is create the layout, and import it in your component, and set it as the value of the component's PageLayout property.

Still confused? Typescript user? Watch this amazing video! It's a great, clear explanation of NextJS layouts and how to render them conditionally!

This is the repository for today's blogpost: https://github.com/professorjrod/layout-test

Thanks so much for reading! This article was a doozy, honestly. Page layouts ain't easy! If you enjoyed this blog post consider giving me a like so other people can find this resource :)

Have a great day and HAPPY CODING!!!

Top comments (2)

Collapse
 
calitomtl profile image
CalitoMTL

Hey @jaredm - I checked out your GitHub and was interested in your StackOverflat project.

I previously worked on a teacher community/collaboration platfrom built in NextJS/Node JS - Coteacher.com - You can try it out or watch a video demo here: youtu.be/P8Lnxemfy84

Now I want to take that platform and turn it into a Stackoverflow style Q&A that can support peer to peer learning across multiple domains.

I'm looking for full stack JS developers to collaborate with. Would this interest you?

Collapse
 
jaredm profile image
professorjrod

Hey, @calitomtl I appreciate you reaching out, I'm flattered! I'm actually working on a biotech stock application at the moment, and that's taking up basically all of my free time-- here's a sneak peek: imgur.com/a/Xr4P6Oj

For finding JS developers to partner with, I would recommend looking for potential partnerships on Reddit or Discord, there are a lot of SAAS communities on those platforms looking for great ideas such as yours.

Thanks again for reaching out and good luck!

Let's Get Hacking

Join the DEV x Linode Hackathon 2022 and use your ingenuity and creativity to build using Linode.

Join the Hackathon <-