NOT MAINTAINED ANYMORE. Please visit my new website at: nikolovlazar.com

Creating Custom Layouts in Next.js

1 year ago

Loading...

3 min read

React's composable nature allows us to create reusable components. Layouts are exactly that! In Next.js there are two ways that you can define a custom layout:

  • Single Shared Layout
  • Per-Page Layouts

Single Shared Layout

#

A Single Shared Layout in Next.js is a custom layout that's used by every page in our app. Let's say our app is simple, and every page has a navbar and a footer. We can define our layout like so:

1// src/components/layout/index.tsx
2
3import type { ReactNode } from 'react';
4
5import Navbar from './navbar';
6import Footer from './footer';
7
8type Props = {
9 children?: ReactNode;
10};
11
12const Layout = ({ children }: Props) => {
13 return (
14 <>
15 <Navbar />
16 <main>{children}</main>
17 <Footer />
18 </>
19 );
20};
21
22export default Layout;

In order to use this custom layout, we can wrap the Component component in our _app.tsx file:

1// pages/_app.tsx
2
3import type { AppProps } from 'next/app';
4
5import Layout from 'src/components/layout';
6
7const App = ({ Component, pageProps }: AppProps) => {
8 return (
9 <Layout>
10 <Component {...pageProps} />
11 </Layout>
12 );
13};
14
15export default App;

Since the Layout component is reused when changing pages, its component state will be preserved.

Per-Page Layouts

#

If we want to have multiple layouts (ex. authentication, dashboard, settings etc...), we can define a getLayout property to our pages that will receive the page in props, and wrap it in the layout that we want. Since we're returning a function, we can have complex nested layouts if we wanted to.

Here's an example of a page:

1// pages/index.tsx
2
3import type { ReactElement } from 'react'
4
5import Layout from 'src/components/layout'
6import NestedLayout from 'src/components/nested-layout'
7
8const Page = () => {
9 return (
10 // Our page's content...
11 )
12}
13
14Page.getLayout = (page: ReactElement) => {
15 return (
16 <Layout>
17 <NestedLayout>{page}</NestedLayout>
18 </Layout>
19 )
20}
21
22export default Page

In order to use this, we need to make some changes in our _app.tsx:

1// pages/_app.tsx
2
3import type { ReactElement, ReactNode } from 'react';
4import type { NextPage } from 'next';
5import type { AppProps } from 'next/app';
6
7type NextPageWithLayout = NextPage & {
8 // define the getLayout method for every page
9 getLayout?: (page: ReactElement) => ReactNode;
10};
11
12type AppPropsWithLayout = AppProps & {
13 // override the default Component definition
14 Component: NextPageWithLayout;
15};
16
17const App = ({ Component, pageProps }: AppPropsWithLayout) => {
18 // use the getLayout defined in each page
19 // if it doesn't exist, provide a fallback
20 const getLayout = Component.getLayout ?? ((page) => page);
21
22 return getLayout(<Component {...pageProps} />);
23};
24
25export default App;

Have in mind that the Custom Layouts are not considered as Pages, so the only way to fetch data is on the client-side.

That's how we can setup a simple mechanism for custom per-page layouts.


Subscribe to my newsletter ✉️

Get emails from me about web development, content creation, and whenever I publish new content.

Subscribe on Substack

HomeBlogColophonTalks

© Lazar Nikolov

Powered by Vercel