Thu Jan 21 2021

How to create a Layout component in Gatsby

Learn how you can share your Navigation and Footer components across all your pages on Gatsby and other React powered frameworks

All websites and web-apps have a navbar component and a footer component. I hope you agree with me when I say that these navbar and footer components should be visible in every page as that is how you create a sense of familiarity with the user. I mean, can you imagine using a website or a web-app where the navbar is different on every page? It would drive me mad!

Now that we have settled this, let's talk about the navbar and the footer component. Since these 2 components are shared across all the pages, it makes no sense for us to be adding them manually onto every page (DRY code is our friend and the beauty of React and its frameworks is the ability to reuse our components). So what we need to do is create a layout component that accepts children and add the navbar and footer over and under it. That way, any content that is wrapped with layout component becomes its children and will be sandwiched between the navbar and footer inside the layout component. Oof, I know that was a lot of reading and some of it might have been tough to grasp. Let me show you what I mean with some code so that you can understand it better and adopt it for your project.

Now you have to remember that I am using Gatsby since its easier to create and work with pages than when I am using create-react-app. But the same principles apply to apps made with create-react-app as they are all based on React.

Let's get your Gatsby project started with this in your command like

1gatsby new gatsby-starter-hello-world

Once you have the new project, the first thing we need is the Layout component. This is important as we first render this is our Index page.

1import React from "react";
2import styles from "../layout/layout.module.css";
3const Layout = ({ children }) => {
4 return (
5 <div className={styles.layout}>
6 <main>{children} </main>
7 </div>
8 );
10export default Layout;

For this component we have a CSS module as we need to do some positioning. If you are not familiar with CSS modules, I have a blog post on it here. The CSS for it is below.

1.layout { display: flex; flex-direction: column; min-height: 100vh;}

Now what is happening in this Layout component is that we are using it as a wrapper on all the pages. Everything that we we wrap with this component is considered its child and is within the <main> tag as all content that is not <nav> and <footer> should be.

What the CSS is doing is making this component a flexbox component and giving it a minimum height of 100vh. You will see this why view height is important when we addthe footer.

Before we move to the next component, make sure you render the Layout component in the index page as I have done below

1import React from "react";
2import Layout from "../components/layout/Layout";
3const IndexPage = () => (
4 <Layout>I am all the content on the page within the navbar and footer</Layout>
6export default IndexPage;

Now we move onto the Navbar component.

1import React from "react";
2const Navbar = () => {
3 return (
4 <header style={{ border: "1px solid black", padding: "1rem 0rem" }}>
5 <nav>I am a navbar</nav>
6 </header>
7 );
9export default Navbar;

Once you have this ready, import it to the Layout component as below

1import React from "react";
2import Navbar from "../navbar/Navbar";
3import styles from "../layout/layout.module.css";
4const Layout = ({ children }) => {
5 return (
6 <div className={styles.layout}>
7 <Navbar />
8 <main>{children} </main>
9 </div>
10 );
12export default Layout;

Once this is done you should be able to see a work of art like this as we are now rendering the Layout component which has the navbar and is wrapped around the content in the Index page.

image of render after adding navbar to layout component

The third component we need is the footer component

1import React from "react";
2import styles from "../footer/footer.module.css";
3const Footer = () => {
4 return <footer className={styles.footer}>I am a footer</footer>;
6export default Footer;

The CSS for it is below.

1.footer {margin-top: auto; border: 1px solid black; padding: 1rem 0rem;}

What is happening in the CSS here is that we are telling it to position itself at the end of the flexbox container that we made the Layout component to be. Since that component had a min height of 100vh, this footer component will be at the bottom.

To see this you need to add the add the footer to the Layout component as below.

1import React from "react";
2import Navbar from "../navbar/Navbar";
3import Footer from "../footer/Footer";
4import styles from "../layout/layout.module.css";
5const Layout = ({ children }) => {
6 return (
7 <div className={styles.layout}>
8 <Navbar />
9 <main>{children} </main>
10 <Footer />
11 </div>
12 );
14export default Layout;

Once this done you should be able to see the below rendered on your index page.

layout component in action

And there you have it! You can now use your Layout component as a wrapper for any page you want and the navbar and the footer will be there on top and under your main content for that page.

If you found what you read helpful, please let me know and follow me on my social media channels for more! If not, you can just sign up to my email newsletter below to be notified of any blog post I publish 😊