How to Use Multiple Layouts in Next.js
What would be the best way to incorporate multiple layouts in our Next.js application?
Define Layouts
Suppose I have two layouts, Layout1
and Layout2
, that I want rendered, depending on the page.
Layout1
might look something like this.
// layouts/Layout1.jsx
const Layout1 = ({ children }) => {
return <div className="layout1">{children}</div>;
};
export default Layout1;
And Layout2
is a drastically different layout.
// layouts/Layout2.jsx
const Layout2 = ({ children }) => {
return <div className="layout2">{children}</div>;
};
export default Layout2;
Example Usage
I considered changing layouts based on routes (i.e. all pages/layout1/*
use Layout1
), but it yielded suboptimal render performance.
I found that the easiest way to change layouts is to define it on the page level.
// pages/home.jsx
const Home = () => <div>Home</div>;
Home.layout = "L1";
export default Home;
// pages/about.jsx
const About = () => <div>About</div>;
About.layout = "L2";
export default About;
Then, inside our _app.jsx
, we can handle all required imports.
// pages/_app.jsx
import Layout1 from "@/layouts/Layout1";
import Layout2 from "@/layouts/Layout2";
const layouts = {
L1: Layout1,
L2: Layout2,
};
const App = ({ Component, pageProps }) => {
const Layout = layouts[Component.layout] || ((children) => <>{children}</>);
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
};
export default App;
Nested Layouts
The provided solution will work very nicely if we don’t require any nested layouts.
If we need multiple, nested layouts, instead of returning a string identifying the layout a page needs, we can return a function of the expected layout.
// pages/home.jsx
import Layout1 from "@/layouts/Layout1";
import Layout2 from "@/layouts/Layout2";
Home.layout = (page) => (
<Layout1>
<Layout2>{page}</Layout2>
</Layout1>
);
// pages/about.jsx
import Layout2 from "@/layouts/Layout2";
import Layout1 from "@/layouts/Layout1";
About.layout = (page) => (
<Layout2>
<Layout1>{page}</Layout1>
</Layout2>
);
Inside _app.jsx
, we can change how we render our components.
// pages/_app.jsx
const pageLayout = Component.layout || ((page) => page);
return pageLayout(<Component {...pageProps} />);